首页 > 解决方案 > 我在微软的逆变示例中遗漏了什么?

问题描述

我试图理解实践中的逆变。看书的时候好像是直截了当的,现在好像卡住了。我知道有很多关于逆变的主题,我用谷歌搜索了很多,没有一个帮助我理解这个特殊问题这是微软文档所说的https://docs.microsoft.com/en-us/dotnet/standard/generics/协方差和逆变

这是我的代码:

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 { } 
}

标签: c#contravariance

解决方案


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

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

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


推荐阅读