2013-05-02 5 views
11

Ich habe zwei verschiedene Möglichkeiten gefunden, einen Delegaten mit einer Aktion zu initialisieren:Aktion zum Delegieren: neue Aktion oder Casting-Aktion?

Eine neue Aktion erstellen oder eine Aktion ausführen.

Delegate foo = new Action(() => DoNothing(param)); 
Delegate bar = (Action)(() => DoNothing(param)); 

Gibt es einen Unterschied zwischen diesen 2 Syntaxen?

Welcher ist besser und warum?

Edit:
Delegieren ist in diesem Beispiel verwenden, da die Syntax ist nützlich Methoden wie BeginInvoke aufrufen oder mit einem Lambda-Ausdruck Invoke, und es ist wichtig, den Lambda-Ausdruck in eine Aktion

static main 
{ 
    Invoke((Action)(() => DoNothing())); // OK 
    Invoke(new Action(() => DoNothing())); // OK 
    Invoke(() => DoNothing()); // Doesn't compil 
} 

private static void Invoke(Delegate del) { } 
zu werfen

Aber es ist interessant zu sehen, dass der Compiler diese autorisiert:

Action action =() => DoNothing(); 
Invoke(action); 
+0

Um deine Bearbeitung verwenden: Was für sinnvoll Inhalt würde es in Ihrer 'static'' Invoke' Methode geben? –

+0

Nichts interessantes. Der Zweck der Frage ist nur, um den Unterschied zwischen den 2 Syntaxen zu verstehen. Meine reale Implementierung ist in einer WPF-Anwendung, wenn ich Dispatcher.Invoke() (http://msdn.microsoft.com/en-us/library/cc647509(v=vs.100).aspx) aufrufen – Hyralex

+1

ich sehe. Sie sollten sich immer noch daran erinnern, dass eine 'Aktion' ___is___ ein 'Delegierter' ist, da 'Aktion' von 'Delegierter' abgeleitet ist. Selbst wenn Sie eine Überladung verwenden, die einen Delegierten aufnimmt, können Sie ihm eine Aktion geben. Beispiel: 'Aktionsleiste =() => DoNothing (param); someDispatcher.BeginInvoke (bar); '(siehe [' Dispatcher.BeginInvoke'] (http://msdn.microsoft.com/de-de/library/cc190824.aspx)). Zusatz: In einer neueren Version des Frameworks, .NET 4.5, gibt es eine Überladung von 'Dispatcher.Invoke', die 'Action' übernimmt, aber nur aus Gründen der Bequemlichkeit, siehe http://msdn.microsoft.com/en-us/library /hh199416.aspx. –

Antwort

10

Es gibt keinen Unterschied zwischen diesen beiden Anweisungen. In beiden Anweisungen wird eine neue Instanz von Action erstellt.

Der folgende IL-Code scheint dies zu bestätigen.

Console Programm:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Delegate barInit = (Action)(() => DoNothing()); 
     Delegate fooInit = new Action(() => DoNothing()); 
    } 

    private static void DoNothing() { } 
} 

IL-Code:

// First instruction 
IL_0000: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2' 
IL_0005: brtrue.s IL_0018 

IL_0007: ldnull 
IL_0008: ldftn void CodeMachineTest.Program::'<Main>b__0'() 

// Create a new Action instance for the instruction (Action)(() => DoNothing()) 
IL_000e: newobj instance void [mscorlib]System.Action::.ctor(object, native int) 

IL_0013: stsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2' 

IL_0018: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2' 
IL_001d: pop 

// Second instruction 
IL_001e: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3' 
IL_0023: brtrue.s IL_0036 

IL_0025: ldnull 
IL_0026: ldftn void CodeMachineTest.Program::'<Main>b__1'() 
IL_002c: newobj instance void [mscorlib]System.Action::.ctor(object, native int) 
IL_0031: stsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3' 

IL_0036: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3' 
IL_003b: pop 
IL_003c: ret 
2

meiner Meinung nach kein Unterschied besteht.

new Action(() => DoNothing(param)); 

Das schafft nur eine neue Aktion und führt entlang einem Lambda-Ausdruck, die die Compiler mit befassen und dafür sorgen, dass alles gut verdrahtet ist. Diese

(Action)(() => DoNothing(param)); 

funktioniert, weil ein Lambda-Verfahren wie diesem keinen Wert zurückgibt und keine Parameter, die als solche der Compiler verifizieren kann, dass es „mappable“ auf eine Aktion der Begründung, dass es den Delegierten System geht.

Sie sind mehr oder weniger ein und dasselbe, abhängig von jeder Art von Compiler-Optimierungen ist es schwer zu sagen, welche performanter ist, vielleicht sollten Sie die Leistung testen und selbst sehen?

Es ist eine interessante Frage und eine Entdeckungsreise in die Delegation System und wie Linq und Ausdrücke passen in

new Func<string>(() => "Boo!"); 

mehr oder weniger entspricht.

(Func<String>)() => "Boo!"; 

Soweit ich Ich bin mir bewusst, dass beide am Ende durch das Delegiertensystem gehen, denke Invoke() usw., es wäre interessant, wenn Sie die Leistung testen und Ihre Ergebnisse teilen würden.

+1

Ich habe einen Test gemacht und es gibt keinen Unterschied. Nach der Demontage sind IL und Maschinencode identisch. – Hyralex

+1

Es ist nicht besonders interessant, sie sind nur zwei Syntaxen, die zu der gleichen IL führen. Das hängt also nicht mit der Performance zusammen. Was soll er also teilen? Lesen Sie die C# -Sprachspezifikation, wenn Sie Details benötigen. Der erste Ausdruck befindet sich in _7.6.10.5 Delegat creation expressions_ und der zweite Ausdruck in _6.5 Anonyme function conversions_. Abschnittsnummern stammen aus Version 5.0 des Dokuments. Beachten Sie, dass 7.6.10.5 eindeutig besagt, dass es genauso verarbeitet wird wie in 6.5. –

0

Es gibt keinen Unterschied, sie sind nur zwei Syntaxen für das gleiche. Persönlich benutze ich das letzte, weil es kürzer ist.

Aber warum brauchen Sie eine Variable vom Typ Delegate? In den meisten Fällen wollen Sie die Variable den gleichen Typ wie die Instanz haben, und dann können Sie

var bar = (Action)(() => DoNothing(param)); 

oder

Action bar =() => DoNothing(param); 

statt

Delegate bar = (Action)(() => DoNothing(param)); // (from your question) 
+0

Einige Methoden wie Invoke oder BeginInvoke benötigen einen Delegaten, und es ist erforderlich, eine Aktion zu generieren oder zu erstellen, um den Lambda-Ausdruck zu verwenden. – Hyralex

+0

@Hyralex Aber alle konkreten Delegattypen, einschließlich 'System.Action', leiten (über' System.MulticastDelegate') von 'System.Delegate' ab. Daher werden die Methoden "Invoke" und "BeginInvoke" und andere Member vererbt. So könnte man z.B. 'Aktionsleiste =() => DoNothing (param); bar.BeginInvoke (...); '. Also ich verstehe es nicht. –

+0

Ich spreche über BeginInvoke und Invoke von bestehenden Objekt wie Dispatcher. Ich habe meine Frage bearbeitet, um mehr Beispiele zu geben. – Hyralex