逆变委托输出结果

本文关键字:输出 结果 | 更新日期: 2023-09-27 18:07:15

我定义了我的类层次结构为Object->Fruit->Apple

class Fruit : object{}
class Apple : Fruit{}

并创建了两个静态方法来处理这些类

    static Fruit FruitProcessor(string fruit)
    {
        return new Fruit();
    }
    static Apple ApplesProcessor(string apple)
    {
        return new Apple();
    }

现在我声明一个委托,没有任何 in, out关键字

public delegate TResult Funk<T, TResult>(T arg);

在我的代码中,我做了以下赋值:

        Funk<string, Fruit> myFunc;
        myFunc = FruitProcessor; // ok, we match signature exactly
        myFunc = ApplesProcessor;// this should not work, but works

由于我没有将结果声明为协变out参数,因此不应该将ApplesProcessor分配给myFunc委托。但这是可能的,程序编译和执行没有任何错误。

如果我改变Funk签名添加out TResult

public delegate TResult Funk<T, out TResult>(T arg);

一切都和以前一样。

这怎么可能?

逆变委托输出结果

这种情况由通常的隐式转换处理。引用相关MSDN页面(https://msdn.microsoft.com/en-us/library/dd233060.aspx):

)
public class First { }
public class Second : First { }
public delegate First SampleDelegate(Second a);
public delegate R SampleGenericDelegate<A, R>(A a);
// Matching signature. 
public static First ASecondRFirst(Second first)
{ return new First(); }
// The return type is more derived. 
public static Second ASecondRSecond(Second second)
{ return new Second(); }
// The argument type is less derived. 
public static First AFirstRFirst(First first)
{ return new First(); }
// The return type is more derived  
// and the argument type is less derived. 
public static Second AFirstRSecond(First first)
{ return new Second(); }
// Assigning a method with a matching signature  
// to a non-generic delegate. No conversion is necessary.
SampleDelegate dNonGeneric = ASecondRFirst;
// Assigning a method with a more derived return type  
// and less derived argument type to a non-generic delegate. 
// The implicit conversion is used.
SampleDelegate dNonGenericConversion = AFirstRSecond;
// Assigning a method with a matching signature to a generic delegate. 
// No conversion is necessary.
SampleGenericDelegate<Second, First> dGeneric = ASecondRFirst;
// Assigning a method with a more derived return type  
// and less derived argument type to a generic delegate. 
// The implicit conversion is used.
SampleGenericDelegate<Second, First> dGenericConversion = AFirstRSecond;

简而言之,在您的确切情况下,您将非泛型委托分配给泛型委托-在这种情况下总是使用隐式转换。要真正使代码失败,您需要做这样的事情:

Funk<string, Fruit> myFunc;
Funk<string, Apple> myAppleFunc = ApplesProcessor;
myFunc = FruitProcessor;
myFunc = myAppleFunc; // Undefined implicit conversion on generic delegate

根据MSDN,自。net 3.5以来,委托返回类型的协方差和委托输入类型的逆变性是隐含的。所以添加inout到你的委托没有区别。

添加此功能的一个原因是,您可以为多个事件分配一个接受EventArgs参数的"香草"事件处理程序,这些事件可能使用从EventArgs派生的更具体的类。例如,您可以使用相同的委托来处理单击按钮和按下键,即使前者传递MouseEventArgs参数,而后者传递KeyEventArgs参数。