5

Delegate我在或下的 Reflector 中找不到 + 运算符MulticastDelegate

我试图弄清楚这不需要演员表:

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);

在第一个样本中,演员是刚刚在封面下完成的吗?

4

4 回答 4

5

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

于 2012-11-25T09:19:53.397 回答
1

在第一个样本中,演员是刚刚在封面下完成的吗?

是的,你可以这么说!

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

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

但是该方法仍然返回一个Actionwhen bothabare Action。是的,a并且b需要具有相同的运行时类型。

请不要写成MulticastDelegate.Combine类定义Combine的方法。因此说,这不那么令人困惑。staticSystem.DelegateDelegate.Combine

車輛改道:

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

Action<string> doSomethingToString; // will be assigned below

Action<ICloneable> a = cloneable => { Console.WriteLine("I'm cloning"); cloneable.Clone(); }
Action<IConvertible> b = convertible => { Console.WriteLine("I'm converting"); convertible.ToInt32(CultureInfo.InvariantCulture); }

Action<string> aStr = a; // OK by contravariance of Action<in T>, aStr and a reference same object
Action<string> bStr = b; // OK by contravariance of Action<in T>, 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>(TDel a, TDel b) where TDel : Delegate
{
  // use typeof(TDel) to figure out type of new "sum" delegate
}

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

于 2012-11-25T09:20:27.390 回答
1

举个例子:

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# 在第一次测试中提供了一些语法糖。

于 2012-11-25T09:23:45.203 回答
0

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

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);
    }
于 2012-11-25T09:33:42.520 回答