Método anônimo em chamada de chamada

Tendo um pouco de dificuldade com a syntax onde queremos chamar um delegado anonimamente dentro de um Control.Invoke.

Nós tentamos várias abordagens diferentes, tudo sem sucesso.

Por exemplo:

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

onde someParameter é local para este método

O acima irá resultar em um erro do compilador:

Não é possível converter o método anônimo para digitar ‘System.Delegate’ porque não é um tipo de delegado

Como o Invoke / BeginInvoke aceita Delegate (em vez de um delegado tipado), é necessário informar ao compilador que tipo de delegado criar; MethodInvoker (2.0) ou Action (3.5) são escolhas comuns (note que eles têm a mesma assinatura); igual a:

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

Se você precisa passar parâmetros, então “variables ​​capturadas” são o caminho:

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

(ressalva: você precisa ser um pouco cauteloso se usar as captações assíncronas , mas a synchronization é boa – ou seja, o acima é bom)

Outra opção é escrever um método de extensão:

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

então:

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

Você pode, claro, fazer o mesmo com BeginInvoke :

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

Se você não puder usar o C # 3.0, poderá fazer o mesmo com um método de instância regular, presumivelmente em uma class base Form .

Na verdade, você não precisa usar a palavra-chave delegada. Apenas passe lambda como parâmetro:

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

Você precisa criar um tipo de delegado. A palavra-chave ‘delegate’ na criação do método anônimo é um pouco enganosa. Você não está criando um delegado anônimo, mas um método anônimo. O método que você criou pode ser usado em um delegado. Como isso:

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

Por uma questão de completude, isso também pode ser feito através de uma combinação de método de ação / método anônimo:

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

Eu tive problemas com as outras sugestões porque às vezes quero retornar valores de meus methods. Se você tentar usar o MethodInvoker com valores de retorno, ele não parece gostar disso. Então a solução que eu uso é assim (muito feliz em ouvir uma maneira de tornar isso mais sucinto – estou usando 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; })); }