2012-11-25 11 views
5

Nie można znaleźć operatora + w reflektorze pod numerem Delegate lub MulticastDelegate.Dlaczego korzystanie z Delegate.Combine wymaga rzutowania, ale użycie operatora + nie działa?

Próbuję dowiedzieć się, w jaki sposób ten nie potrzebuje Obsada:

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

Action c = a + b; 

Ale to robi:

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

Action c = (Action)MulticastDelegate.Combine(a, b); 

w pierwszej próbce jest obsada właśnie zrobione pod kołdrą ?

Odpowiedz

1

Biorąc następujący przykład:

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

Wtedy, patrząc na niego z 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(); 
    } 
} 

Wydaje się, że robią dokładnie to samo, tylko C# jest zapewnienie sobie cukier syntaktyczny w pierwszym badaniu .

4

+= i -= jest realizowany na poziomie języka (tj z kompilatora pomoc) ze znanymi typami delegatów, więc nie potrzebuje obsady, natomiast Delegate.Combine jest tylko zwykłym (non-generic) Metoda z Delegate typ zwracany, więc potrzebuje obsady.

1

W pierwszej próbce jest obsada właśnie zrobiona pod kołdrą?

Tak, możesz tak powiedzieć!

Metoda Combine została napisana w .NET 1, gdzie nie istniał ogólny C#. Dlatego formalny typ powrót Combine musiał być Delegate:

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

Jednak metoda nadal zwraca Action gdy zarówno a i bAction. I tak, a i b są wymagane do tego samego typu środowiska wykonawczego.

Nie pisz MulticastDelegate.Combine jako Combine jest metodą static zdefiniowaną przez klasę System.Delegate. Dlatego powiedzmy: Delegate.Combine, to mniej mylące.

Objazd:

Aktualna wersja C# i Combine ma problemy z kontrawariantny typów delegatów. Rozważmy następujący:

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 

Teraz załóżmy, że jakiś przyszły wersja ramach wprowadziła ogólny Combine metody:

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

i załóżmy C# został zmieniony w taki sposób, + został przetłumaczony na wywołanie nowy generic Combine<> metoda, a następnie połączenie kontrawariancji i delegacji zostanie naprawione! Sądzę, że mówią nam, że mają wyższe priorytety, ale wciąż.

+1

Czy istnieje jakikolwiek problem z podstawowym każdy typ delegata definiuje własną metodę statyczną 'Combine'? Następnie, jeśli dwóch delegatów "X" i "Y" było obu typów, które można podstawić do 'FooDelegate', można użyć' FooDelegate.Combine (X, Y) '. Nawet bez kwestii kowariancji, wydaje się to czystsze niż '(FooDelegate) Delegate.Combine (X, Y)' i może dodać sprawdzanie w czasie kompilacji, że odpowiednie były 'X' i' Y'. – supercat

+0

@supercat Dla mnie brzmi to jak dobre rozwiązanie. –

0

Wykonuje się to przy użyciu "przeciążenia operatora", możesz to zrobić również we własnych obiektach.

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; 

Wynik: o3.Property = "Witaj, świecie!"

Więc zakładam można zorganizować wykonuje somthing tak w tle

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

O tak, wiem o przeciążeniu operatora, po prostu nie mogłem go znaleźć w Reflactor i zastanawiałem się jak to zrobili –

Powiązane problemy