为什么使用Delegate.Combine需要强制转换但使用+运算符不?

我在DelegateMulticastDelegate下的Reflector中找不到+运算符。

我想弄清楚这不需要演员如何:

 Action a = () => Console.WriteLine("A"); Action b = () => Console.WriteLine("B"); Action c = a + b; 

但这样做:

 Action a = () => Console.WriteLine("A"); Action b = () => Console.WriteLine("B"); Action c = (Action)MulticastDelegate.Combine(a, b); 

在第一个样品中是刚刚在封面下完成的铸造?

以下面的例子为例:

 class Program { static void Main(string[] args) { Test1(); Test2(); } public static void Test1() { Action a = () => Console.WriteLine("A"); Action b = () => Console.WriteLine("B"); Action c = a + b; c(); } public static void Test2() { Action a = () => Console.WriteLine("A"); Action b = () => Console.WriteLine("B"); Action c = (Action)MulticastDelegate.Combine(a, b); c(); } } 

然后用ILSpy查看它:

 internal class Program { private static void Main(string[] args) { Program.Test1(); Program.Test2(); } public static void Test1() { Action a = delegate { Console.WriteLine("A"); }; Action b = delegate { Console.WriteLine("B"); }; Action c = (Action)Delegate.Combine(a, b); c(); } public static void Test2() { Action a = delegate { Console.WriteLine("A"); }; Action b = delegate { Console.WriteLine("B"); }; Action c = (Action)Delegate.Combine(a, b); c(); } } 

似乎他们完全一样,只是C#在第一次测试中提供了一些语法糖。

+=-=在语言级别(即使用编译器帮助)实现,具有已知的委托类型,因此它不需要强制转换,而Delegate.Combine只是一个具有Delegate返回类型的普通(非generics)方法,所以它需要演员。

在第一个样品中是刚刚在封面下完成的铸造?

是的,你可以这么说!

Combine方法是用.NET 1编写的,其中不存在通用的C#。 因此,正式返回类型的Combine必须是Delegate

 public static Delegate Combine(Delegate a, Delegate b) { ... } 

但是当ab都是Action时,该方法仍返回Action 。 是的, ab需要具有相同的运行时类型。

请不要编写MulticastDelegate.Combine因为CombineSystem.Delegate类定义的static方法。 因此,请说Delegate.Combine ,这不那么令人困惑。

车辆改道:

当前版本的C#和Combine存在逆变委托类型的问题。 考虑以下:

 Action doSomethingToString; // will be assigned below Action a = cloneable => { Console.WriteLine("I'm cloning"); cloneable.Clone(); } Action b = convertible => { Console.WriteLine("I'm converting"); convertible.ToInt32(CultureInfo.InvariantCulture); } Action aStr = a; // OK by contravariance of Action, aStr and a reference same object Action bStr = b; // OK by contravariance of Action, bStr and b reference same object doSomethingToString = aStr + bStr; // throws exception doSomethingToString("42"); // should first clone "42" then convert "42" to Int32 

现在,假设该框架的未来版本引入了一个通用的Combine方法:

 public static TDel Combine(TDel a, TDel b) where TDel : Delegate { // use typeof(TDel) to figure out type of new "sum" delegate } 

并假设C#被更改为+被转换为对新通用Combine<>方法的调用,然后将修复逆向和委托组合! 我猜他们告诉我们他们有更高的优先级,但仍然。

它使用“运算符重载”完成,您可以在自己的对象中执行此操作。

 public class MyObject { public string Property { get; set; } public MyObject(string property) { this.Property = property; } public static MyObject operator +(MyObject a1, MyObject a2) { return new MyObject(a1.Property + a2.Property); } } MyObject o1 = new MyObject("Hello"); MyObject o2 = new MyObject(" World!"); MyObject o3 = o1 + o2; 

结果:o3.Property =“Hello World!”

所以我假设框架在后台执行这样的事情

  public static Action operator +(Action a1, Action a2) { return (Action)MulticastDelegate.Combine(a1,a2); }