2010-09-29 24 views
9

J'ai remarqué quelques exemples de choses qui fonctionnent et qui ne fonctionnent pas avec les fonctions lambda et les délégués anonymes en C#. Que se passe t-il ici?Comment fonctionne le typage délégué/lambda et la coercition?

class Test : Control { 
    void testInvoke() { 
     // The best overloaded method match for 'Invoke' has some invalid arguments 
     Invoke(doSomething); 

     // Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type 
     Invoke(delegate { doSomething(); }); 

     // OK 
     Invoke((Action)doSomething); 

     // OK 
     Invoke((Action)delegate { doSomething(); }); 

     // Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type 
     Invoke(() => doSomething()); 

     // OK 
     Invoke((Action)(() => doSomething())); 
    } 

    void testQueueUserWorkItem() { 
     // The best overloaded method match for 'QueueUserWorkItem' has some invalid arguments 
     ThreadPool.QueueUserWorkItem(doSomething); 

     // OK 
     ThreadPool.QueueUserWorkItem(delegate { doSomething(); }); 

     // The best overloaded method match for 'QueueUserWorkItem' has some invalid arguments 
     ThreadPool.QueueUserWorkItem((Action)doSomething); 

     // No overload for 'doSomething' matches delegate 'WaitCallback' 
     ThreadPool.QueueUserWorkItem((WaitCallback)doSomething); 

     // OK 
     ThreadPool.QueueUserWorkItem((WaitCallback)delegate { doSomething(); }); 

     // Delegate 'WaitCallback' does not take '0' arguments 
     ThreadPool.QueueUserWorkItem(() => doSomething()); 

     // OK 
     ThreadPool.QueueUserWorkItem(state => doSomething()); 
    } 

    void doSomething() { 
     // ... 
    } 
} 

Eh bien c'est beaucoup d'exemples. Je suppose que mes questions sont les suivantes:

  1. Pourquoi Invoke refuse toujours une fonction lambda ou un délégué anonyme, mais ThreadPool.QueueUserWorkItem ne très bien?

  2. Que diable ne "Impossible de convertir la méthode anonyme pour taper 'System.Delegate' parce que ce n'est pas un type de délégué" signifie quand même?

  3. Pourquoi ThreadPool.QueueUserWorkItem accepte un délégué anonyme sans paramètres, mais pas une expression lambda sans paramètre?

Répondre

9
  1. ThreadPool.QueueUserWorkItem a un délégué spécifique dans sa signature; Invoke a juste Delegate. Les expressions lambda et les méthodes anonymes peuvent uniquement être converties en un type de délégué spécifique.

  2. C'est juste un mauvais message d'erreur. Cela signifie: "Je ne sais pas exactement quel type de délégué vous voulez convertir."

  3. Vous utilisez une méthode anonyme sans aucune liste de paramètres qui peut être convertie en n'importe quel type de délégué qui n'utilise pas les paramètres out/ref. Si vous avez essayé delegate() { ... } (c'est-à-dire une liste de paramètres explicitement vide), cela ne fonctionnerait pas. Cette fonctionnalité "Je ne me soucie pas des paramètres" des méthodes anonymes est la seule fonctionnalité ils ont ce que les expressions lambda ne font pas.

Il est plus facile de démontrer tout cela dans le cadre des missions simples, l'OMI:

// Doesn't work: no specific type 
Delegate d =() => Console.WriteLine("Bang"); 

// Fine: we know the exact type to convert to 
Action a =() => Console.WriteLine("Yay"); 

// Doesn't work: EventHandler isn't parameterless; we've specified 0 parameters 
EventHandler e1 =() => Console.WriteLine("Bang"); 
EventHandler e2 = delegate() { Console.WriteLine("Bang again"); }; 

// Works: we don't care about parameter lists 
EventHandler e = delegate { Console.WriteLine("Lambdas can't do this"); }; 
+4

Et je pensais que je compris les délégués et les lambdas. J'étais tellement stupide. – recursive

+0

Bonnes choses comme toujours, +1 pour "... est la seule caractéristique qu'ils ont les expressions lambda pas." – Ani

+1

@recursive, si vous souhaitez en savoir plus, lisez les arbres d'expression. Ce qui est intéressant avec les expressions lambda, c'est qu'elles sont en réalité _expressions_, avec un modèle descriptif riche pour ce qui est exprimé, et pas simplement un raccourci syntaxique pour passer la logique à un paramètre délégué. C'est ce qui permet à la magie comme LINQ to SQL de se produire. http://msdn.microsoft.com/en-us/library/bb397951.aspx –