【问题标题】:Contravariant delegate output result逆变委托输出结果
【发布时间】:2015-08-10 15:58:59
【问题描述】:

我将我的类层次结构定义为 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

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

如果我更改 Funk 签名以添加 out TResult

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

一切都和以前一样。

这怎么可能?

【问题讨论】:

  • 这不是what you asked earlier,而是使用方法而不是lambdas?我认为这两个都包含在作为重复链接的问题中......? IE 如果您使用的是 lambda,您 可以 使签名匹配,所以您 必须 使其匹配?但是对于方法,这不是强制的吗?
  • 这是一个稍微不同的问题。上一篇是关于反义函数的特殊解释。这似乎是由 .NET 3.5 更改引起的。

标签: c# delegates covariance


【解决方案1】:

这种情况由通常的隐式转换处理。引用相关的 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

【讨论】:

    【解决方案2】:

    根据MSDN,从 .NET 3.5 开始隐含委托返回类型的协变和委托输入类型的逆变。因此,将 inout 添加到您的委托没有任何区别。

    添加它的一个原因是,您可以将接受EventArgs 参数的“普通”事件处理程序分配给多个事件,这些事件可能使用派生自EventArgs 的更具体的类。例如,您可以使用相同的委托来处理按钮单击和按键操作,即使前者传递了 MouseEventArgs 参数,而后者传递了 KeyEventArgs 参数。

    【讨论】:

    • inout 不能与默认行为不同。如果你做参数out,你会得到编译器错误。您可以将其设为in,或者保持原样,默认情况下它将被视为in
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    • 1970-01-01
    • 2010-09-17
    • 1970-01-01
    • 2012-08-27
    • 1970-01-01
    相关资源
    最近更新 更多