【问题标题】:Combining delegates and contravariance结合代表和逆变
【发布时间】:2011-05-19 23:19:08
【问题描述】:

文章声明如下:http://msdn.microsoft.com/en-us/library/dd799517.aspx

差异不适用于委托组合。也就是说,给定两个类型为Action<Derived>Action<Base>(Visual Basic 中为Action(Of Derived)Action(Of Base))的委托,您不能将第二个委托与第一个委托组合,尽管结果是类型安全的。 Variance 允许将第二个委托分配给Action<Derived> 类型的变量,但只有当它们的类型完全匹配时,委托才能组合。

Action<B> baction = (taret) => { Console.WriteLine(taret.GetType().Name); };
Action<D> daction = baction;
Action<D> caction = baction + daction;

上述代码中bactiondaction采用不同的参数。但我仍然能够将它们结合起来。 我错过了什么?

TIA。

【问题讨论】:

  • 在您的示例中,bactiondaction 是对同一对象的引用。因此baction.GetType() == daction.GetType() 当然,因为它是同一个实例。当两个委托对象不同并且具有不同的运行时类型时,就会出现问题。现在, .NET 4.0 之前,对于每个委托对象,运行时类型和编译时类型是一致的,因为委托是(密封类型和)不变的。但在 .NET 4.0 和 C# 4 及更高版本中,编译时 Action&lt;string&gt; 可能是运行时 Action&lt;object&gt;Action&lt;ICloneable&gt;Action&lt;IEnumerable&lt;char&gt;&gt; 等等。

标签: c#


【解决方案1】:

文档不清楚,我同意。

问题是两个组合委托的 runtime 类型必须匹配。这意味着存在 compile time 类型匹配但 runtime 类型不匹配的场景。

考虑例如:

Func<string> f1 = ()=>"";
Func<object> f2 = ()=>null;
Func<object> f3 = f1; // legal in C# 4 because of covariance
Func<object> f4 = f2 + f3;

这在编译时是合法的;您正在添加两个相同编译时类型的委托。但是在运行时它会失败,因为 runtime 要求 runtime 类型 完全匹配。

这是 CLR 类型系统中的一个不幸漏洞。我希望有一天我们能把它修好,但没有承诺。

【讨论】:

  • 你外交上没有指出现在正在工作的部分是负责的部分。
  • 我认为部分困难在于不一定有一种推断最佳类型的方法是否正确? Action> 和 Action> 都派生自 Action>,如果给定 T 和派生自 Action> 的两个委托,当然可以编写代码产生一个 Action> 依次执行这两个动作。然而,给定一个 Action> 和 Action>,如果不被告知组合的委托应该是一个 Action>,系统就无法知道。跨度>
  • @supercat:首先,准确地说:Action> 源自 System.MulticastDelegate。它可以通过引用转换隐式转换为 Action>。撇开挑剔不谈,是的,您在这里发现了一个真正的问题。
  • @Eric Lippert:关于派生与可兑换性的观点。在某些方面,我希望委托是一个接口而不是类类型;然而,如果没有泛型,这样的设计将毫无用处,并且当泛型添加到 .net 2.0 时,委托已经很好地建立起来了。如果委托是一种接口类型,那么像闭包这样的东西只需要创建一个对象实例而不是两个。我想知道这种设计的更广泛意义是什么?
  • @nawfal:这不是逻辑问题,而是实现问题。基本上,CLR 中处理委托组合的代码不能很好地处理这些协变场景。
猜你喜欢
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 2021-02-07
  • 1970-01-01
  • 2018-11-29
  • 2016-07-27
  • 1970-01-01
相关资源
最近更新 更多