我在微软的逆变例子中缺少什么?

时间:2018-05-02 14:11:27

标签: c# contravariance

我试图理解实践中的逆转。当我读这本书时似乎很简单,但现在我似乎已经卡住了。 我知道有很多关于逆变的主题,我用Google搜索了很多,没有人帮助我理解这个特殊的问题 以下是Microsoft文档所说的https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance

这是我的代码:

using static System.Console;

namespace CSharpTests 
{
    class Program 
    {
        delegate void Action<T> (T obj);

        static void Main(string[] args) 
        {

            Action<Device> b = DeviceAction;
            Action<Mouse> d = b; // Error cannot implicitly convert type CSharpTests.Program.Action<CSharpTests.Device> to CSharpTests.Program.Action<CSharpTests.Mouse>
            d(new Mouse());

            ReadLine();
        }

        private static void DeviceAction(Device target) {
            WriteLine(target.GetType().Name);
        }
    }
    class Device { }
    class Mouse : Device { } 
}

关键区别是什么?我的代码甚至没有编译。正如你所看到的,我有一个代表接受泛型类型,据我所知,它允许相反的变换。但在实践中,我得到了一个编译时错误。 我也尝试使用“out”参数并获得相同的错误

using static System.Console;

namespace CSharpTests {

    class Program {

        delegate void Action<T> (out T obj);

        static void Main(string[] args) {

            Action<Device> b = DeviceAction;
            Action<Mouse> d = b; // Error cannot implicitly convert type CSharpTests.Program.Action<CSharpTests.Device> to CSharpTests.Program.Action<CSharpTests.Mouse>
            Mouse m;
            d(out m);

            ReadLine();
        }

        private static void DeviceAction(out Device target) {
            target = new Device();
            WriteLine(target.GetType().Name);
        }
    }
    class Device { }
    class Mouse : Device { } 
}

3 个答案:

答案 0 :(得分:3)

您要使用T 参数声明一个不变的out

delegate void Action<T> (out T obj);

out移至Action<out T>会为您提供协变T 。你想要做的是这个(带有参数的逆变T):

delegate void Action<in T> (T obj);

答案 1 :(得分:3)

将签名更改为delegate void Action<in T>(T arg)

将类型参数声明为in表示违反; out表示协方差。

您通常可以告诉使用哪一个,因为in用于输入(例如,参数)而out用于输出(例如,返回值)。

答案 2 :(得分:-1)

你创建一个target = new Device(); 这和你输入的内容不一样......

试试这样:

[TestClass]
public class Method_Tetsts
{
    class Device { }
    class Mouse : Device { }

    [TestMethod]
    public void ActionTest()
    {

        void DeviceAction<T>( T target)
        {  
            Assert.AreEqual(target.GetType().Name, "Mouse");
        }

        Action<Device> b = DeviceAction;
        Action<Mouse> d = b; // Error cannot implicitly convert type CSharpTests.Program.Action<CSharpTests.Device> to CSharpTests.Program.Action<CSharpTests.Mouse>
        d(new Mouse());
    }
}