我在微软的逆变示例中遗漏了什么?

What am I missing in Microsoft's contravariance example?

我正在尝试理解实践中的逆变。看书的时候好像很直白,现在好像卡住了。 我知道有很多关于逆变的话题,我用谷歌搜索了很多,none 帮助我理解了这个特殊问题 这是 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 { } 
}

在这里你声明了一个不变量 Tout 参数:

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

out 移动到 Action<out T> 会给你一个 协变 T。你想要做的是这个(一个带有参数的逆变 T):

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

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

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

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

好吧,你创建了一个目标 = 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());
    }
}