2010-02-05 14 views
7
interface IBar { void Hidden(); } 

class Foo : IBar { public void Visible() { /*...*/ } void IBar.Hidden() { /*...*/ } } 

class Program 
{ 
    static T CallHidden1<T>(T foo) where T : Foo 
    { 
     foo.Visible(); 
     ((IBar)foo).Hidden(); //Cast required 

     return foo; 
    } 

    static T CallHidden2<T>(T foo) where T : Foo, IBar 
    { 
     foo.Visible(); 
     foo.Hidden(); //OK 

     return foo; 
    } 
} 

Y a-t-il une différence (CallHidden1 vs. CallHidden2) est du code compilé réel? Existe-t-il d'autres différences entre où T: Foo et où T: Foo, IBar (si Foo implémente IBar) qu'en accédant aux membres d'interface explicitement implémentés?Interface implicitement implémentée et contrainte générique

Répondre

1

Oui, un petit bit, puisque le second spécifie que l'interface doit être implémentée, ce qui peut devenir important si Foo est modifié ultérieurement afin qu'il n'implémente pas IBar.

qui le rendrait impropre à être utilisé dans CallHidden2<> tout en restant valables au moment de la compilation pour CallHidden1<> (qui serait alors l'échec à l'exécution si IBar n'est plus mis en oeuvre par Foo). Donc, si elles sont dans des assemblages séparés, les différentes métadonnées feront une différence. L'IL exécuté sera cependant assez similaire sinon identique.

6

L'IL généré est légèrement différente:

L_000d: ldarg.0 
    L_000e: box !!T 
    L_0013: callvirt instance void WindowsFormsApplication1.IBar::Hidden() 

contre

L_000d: ldarga.s foo 
    L_000f: constrained !!T 
    L_0015: callvirt instance void WindowsFormsApplication1.IBar::Hidden() 

Si T étaient un type de valeur, il en résulterait foo étant encaissée CallHidden1 mais pas dans CallHidden2. Cependant, puisque Foo est une classe, tout type T dérivé de Foo ne sera pas un type de valeur, et donc le comportement sera identique.