2008-10-31 14 views
113

Posiadanie trochę problemów ze składnią, w której chcemy anonimowo wezwać delegata w Control.Invoke.Anonimowa metoda w wywołaniu Invoke

Próbowaliśmy wielu różnych podejść, wszystko bez skutku.

Na przykład:

myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); }); 

gdzie someParameter jest lokalny do tej metody

Powyższe spowoduje błąd kompilatora:

Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type

Odpowiedz

200

Ponieważ Invoke/BeginInvoke akceptuje Delegate (zamiast wpisywanych delegata), musisz poinformować kompilator, jaki typ delegata do stworzenia; MethodInvoker (2.0) lub Action (3.5) są typowymi wyborami (zauważ, że mają ten sam podpis); tak:

control.Invoke((MethodInvoker) delegate {this.Text = "Hi";}); 

Jeśli trzeba przejść w parametrach, a następnie „złapanych zmienne” są sposobem:

string message = "Hi"; 
control.Invoke((MethodInvoker) delegate {this.Text = message;}); 

(uwaga: trzeba być nieco ostrożny w przypadku korzystania przechwytuje asynchroniczny , ale sync jest w porządku - czyli powyżej jest w porządku)

Innym rozwiązaniem jest napisać metodę rozszerzenia:

public static void Invoke(this Control control, Action action) 
{ 
    control.Invoke((Delegate)action); 
} 

następnie:

this.Invoke(delegate { this.Text = "hi"; }); 
// or since we are using C# 3.0 
this.Invoke(() => { this.Text = "hi"; }); 

Można oczywiście zrobić to samo z BeginInvoke:

public static void BeginInvoke(this Control control, Action action) 
{ 
    control.BeginInvoke((Delegate)action); 
} 

Jeśli nie można używać C# 3.0, można zrobić to samo ze zwykłym metody instancji , prawdopodobnie w klasie bazowej Form.

+0

Jak można przekazuję parametry do twojego pierwszego rozwiązania w tej odpowiedzi? Miałem na myśli to rozwiązanie: control.Invoke ((MethodInvoker) delegate {this.Text = "Hi";}); – uzay95

+1

Dlaczego metoda Extension jest wywoływana bez konieczności jawnego przesyłania do działania? –

+0

Ponieważ kompilator może wywnioskować, że z użycia. – RoboJ1M

13
myControl.Invoke(new MethodInvoker(delegate() {...})) 
13

trzeba utworzyć delegata rodzaj. Słowo kluczowe "deleguj" w tworzeniu anonimowej metody jest nieco mylące. Nie tworzysz anonimowego delegata, ale anonimową metodę. Utworzoną metodę można wykorzystać w delegacie. Tak:

myControl.Invoke(new MethodInvoker(delegate() { (MyMethod(this, new MyEventArgs(someParameter)); })); 
+0

myślę, że to powinna być prawidłowa odpowiedź na to pytanie – electricalbah

42

W rzeczywistości nie trzeba używać słowa kluczowego delegowanego. Wystarczy podać lambdę jako parametr:

control.Invoke((MethodInvoker)(() => {this.Text = "Hi"; })); 
5

Miałem problemy z innymi sugestiami, ponieważ chcę czasami zwracać wartości z moich metod. Jeśli spróbujesz użyć metody MethodInvoker z wartościami zwracanymi, wydaje się, że nie podoba ci się to. Tak więc rozwiązanie, którego używam, jest takie (bardzo chętnie usłyszysz sposób, aby uczynić to bardziej zwięzłym - używam C# .net 2.0):

// Create delegates for the different return types needed. 
    private delegate void VoidDelegate(); 
    private delegate Boolean ReturnBooleanDelegate(); 
    private delegate Hashtable ReturnHashtableDelegate(); 

    // Now use the delegates and the delegate() keyword to create 
    // an anonymous method as required 

    // Here a case where there's no value returned: 
    public void SetTitle(string title) 
    { 
     myWindow.Invoke(new VoidDelegate(delegate() 
     { 
      myWindow.Text = title; 
     })); 
    } 

    // Here's an example of a value being returned 
    public Hashtable CurrentlyLoadedDocs() 
    { 
     return (Hashtable)myWindow.Invoke(new ReturnHashtableDelegate(delegate() 
     { 
      return myWindow.CurrentlyLoadedDocs; 
     })); 
    } 
7

Dla kompletności, może to być również realizowane za pośrednictwem/anonimowego połączeniu METODA Działanie:

//Process is a method, invoked as a method group 
Dispatcher.Current.BeginInvoke((Action) Process); 
//or use an anonymous method 
Dispatcher.Current.BeginInvoke((Action)delegate => { 
    SomeFunc(); 
    SomeOtherFunc(); 
});