2009-05-14 4 views
5

Voir les quatre lignes dans la méthode ci-dessous Go():La différence entre la création de délégué implicite et explicite (avec et sans médicaments génériques)

delegate void Action<T>(T arg); 
delegate void Action(); 

void DoSomething<T>(Action<T> action) 
{ 
    //... 
} 

void DoSomething(Action action) 
{ 
    //... 
} 

void MyAction<T>(T arg) 
{ 
    //... 
} 

void MyAction() 
{ 
    //... 
} 

void Go<T>() 
{ 
    DoSomething<T>(MyAction<T>); // throws compiler error - why? 
    DoSomething(new Action<T>(MyAction<T>)); // no problems here 
    DoSomething(MyAction); // what's the difference between this... 
    DoSomething(new Action(MyAction)); // ... and this? 
} 

Notez que l'erreur du compilateur généré par le premier appel est: Les arguments de type pour la méthode 'Action (T)' ne peuvent pas être déduits de l'utilisation. Essayez de spécifier explicitement les arguments de type.

+0

Je ne peux pas comprendre comment cela compilerait (en vase clos): void doSomething (Action d'action) { // ...} Puisque T est pas déclaré ... Est-ce la chose à l'intérieur une classe générique? –

+0

Oui, je modifie mon exemple maintenant. Doit avoir lu Go () {... –

+0

Est-ce moi mais quand je compile le code que vous avez ici, il compile sans erreur.En supposant que je place le code dans une classe non générique. J'utilise C# 3.5 SP1 – JoshBerke

Répondre

13

Il n'y a pas de différence entre MyAction et new Action(MyAction) (quand ils sont à la fois valides) autre que l'ancien ne fonctionnera pas en C# 1. Ceci est un implicit method group conversion. Il y a des moments où cela n'est pas applicable, le plus notable lorsque le compilateur ne peut pas déterminer quel genre de délégué vous voulez, par exemple.

Delegate foo = new Action(MyAction); // Fine 
Delegate bar = MyAction; // Nope, can't tell target type 

Ceci entre en jeu dans votre question car les deux méthodes impliquées sont surchargées. Cela conduit à des maux de tête, essentiellement. En ce qui concerne les génériques - c'est intéressant. Les groupes de méthodes n'obtiennent pas beaucoup d'amour de l'inférence de type C# 3 - je ne suis pas sûr que cela va être amélioré dans C# 4 ou non. Si vous appelez une méthode générique et spécifiez l'argument de type, l'inférence de type fonctionne assez bien - mais si vous essayez de le faire dans l'autre sens, il échoue:

using System; 

class Test 
{ 
    static void Main() 
    { 
     // Valid - it infers Foo<int> 
     DoSomething<int>(Foo); 
     // Valid - both are specified 
     DoSomething<int>(Foo<int>); 
     // Invalid - type inference fails 
     DoSomething(Foo<int>); 
     // Invalid - mismatched types, basically 
     DoSomething<int>(Foo<string>); 
    } 

    static void Foo<T>(T input) 
    { 
    } 

    static void DoSomething<T>(Action<T> action) 
    { 
     Console.WriteLine(typeof(T)); 
    } 
} 

inférence de type en C# 3 est très compliqué, et fonctionne bien dans la plupart des cas (en particulier c'est génial pour LINQ) mais échoue dans quelques autres. Dans un monde idéal, il deviendrait plus facile de comprendre et plus puissant dans les futures versions ... nous verrons!

+0

À la votre! J'ai accepté l'autre réponse mais la tienne est toujours utile aussi. +1 –

3

La création de délégué implicite non-générique est juste du sucre syntaxique, de sorte que le compilateur génère exactement le même code pour

DoSomething(MyAction); 

et

DoSomething(new Action(MyAction)); 

comme il peut déduire le type du délégué directement à partir des arguments de méthode & contexte. Avec le délégué générique, vous devez spécifier le type de délégué dû à la covariance et à la contravariance (voir http://msdn.microsoft.com/en-us/library/ms173174(VS.80).aspx pour plus de détails) - le T dans Action peut être un supertype du T dans la méthode, et il sera toujours accepté comme une méthode de délégué. Donc, vous devez spécifier explicitement le T dans le délégué car le compilateur ne peut pas le comprendre lui-même.

+0

A bientôt, je comprends. Lien vers covariance vs contravariance article pour ceux qui ne comprennent pas: http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) –

+0

Je dirais que c'est plus à faire avec les limitations de l'inférence de type que co/contravariance, personnellement. Si vous lisez la section des spécifications sur l'inférence de type (je ne m'en souviens pas maintenant), vous verrez que les groupes de méthodes n'ont pratiquement aucune chance. –

1

Juste un sidenote .. Pour une raison quelconque cela fonctionne dans VB.

Semble la mise en œuvre du préprocesseur en C# et VB diffèrent quand je viens de convertir le Methodgroup/adderessof en un délégué.