2010-05-20 11 views
0

Lorsque je travaille avec des implémentations d'interface explicites en C#, il est souvent nécessaire de lancer un objet sur l'une de ses interfaces pour accéder à un membre de cette interface. En raison de la fiabilité et de la facilité de maintenance améliorées offertes par la vérification du type de temps de compilation, j'ai toujours préféré utiliser des conversions implicites pour effectuer cela. La seule façon dont je sais de faire cela implique deux lignes de code et introduit une autre variable dans la portée. Voici un exemple:Accès sécurisé et simple aux membres de l'interface explicite en C#

public interface IMyType 
{ 
    string SayHello(); 
} 

public class MyType : IMyType 
{ 
    string IMyType.SayHello() { return "Hello!"; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var item = new MyType(); 

     // Option 1 - Implicit cast. Compile time checked but takes two lines. 
     IMyType item2 = item; 
     System.Console.WriteLine(item2.SayHello()); 

     // Option 2 - One line but risks an InvalidCastException at runtime if MyType changes. 
     System.Console.WriteLine(((IMyType)item).SayHello()); 

     // Option 3 - One line but risks a NullReferenceException at runtime if MyType changes. 
     System.Console.WriteLine((item as IMyType).SayHello()); 
    } 
} 

Parce que le compilateur sait que MyType outils IMyType Je suppose qu'un casting implicite est mieux qu'un explicite car un changement plus tard à la déclaration de MyType entraînera une erreur de compilation au lieu d'un InvalidCastException à l'exécution. Cependant, je préfère quelque peu la simplicité de la syntaxe de transtypage explicite et l'ai souvent utilisée dans le code d'autres personnes.

Ma question est triple:

  • Laquelle des options ci-dessus ne vous préférez (et pourquoi)?
  • Y a-t-il une meilleure façon de faire cela?
  • Quelles sont les meilleures pratiques pour effectuer des conversions explicites lorsque des conversions implicites sont possibles?

Répondre

2

Voici une compilation vérifié une doublure:

public static class Converter 
{ 
    public static T ReturnAs<T>(T item) 
    { 
     return item; 
    } 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     var item = new MyType(); 

     // Option 1 - Implicit cast. Compile time checked but takes two lines. 
     IMyType item2 = item; 
     System.Console.WriteLine(item2.SayHello()); 

     // Option 2 - One line but risks an InvalidCastException at runtime if MyType changes. 
     System.Console.WriteLine(((IMyType)item).SayHello()); 

     // Option 3 - One line but risks a NullReferenceException at runtime if MyType changes. 
     System.Console.WriteLine((item as IMyType).SayHello()); 

     // Option 4 - compile time one liner 
     Converter.ReturnAs<IMyType>(item).SayHello(); 
    } 
} 
+0

Bon point. Cela fonctionne encore mieux avec les méthodes d'extension. –

1

En réponse aux trois questions: Fiez-vous aux distributions implicites en règle générale. Vous programmez sur l'interface, pas sur l'implémentation. Comme pour le dernier, si vous devez vraiment compter sur la programmation par rapport à une implémentation (une classe dérivée spécifique) alors assurez-vous que l'objet peut être lancé avant d'essayer de faire quoi que ce soit avec lui. Quelque chose comme ceci:

var IMyType item3 = item as MyConcreteType; 
if(item3 != null) { 
    item3.SayHello(); 
} 
+0

+1 Je suis d'accord avec se fondant sur des conversions implicites en règle générale. C'est plus élégant à mon avis. –

-1

Je habituellement comme comme:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var item = new MyType(); 
     if(item is IMyType){ 
      Console.WriteLine((item as IMyType).SayHello()); 
     } 
     else { /* Do something here... */ } 

    } 
} 
+2

vous appliquez le casting deux fois inutilement. Vous devriez faire le "as" en premier, puis simplement faire une vérification nulle. –

0

Si vous n'êtes pas sûr que l'objet est une instance de l'interface puis effectuez une vérification comme/null. Habituellement, vous renvoyez une interface à partir d'un appel de méthode/fonction auquel cas vous la stockez simplement dans une variable sans cast (bien que la vérification de null puisse toujours être nécessaire).