Domanda

Quando sto lavorando con le implementazioni di interfaccia esplicite in C #, diventa spesso necessario inserire un oggetto in una delle sue interfacce, al fine di accedere a un membro di tale interfaccia. A causa della maggiore affidabilità e manutenibilità offerta dalla compilazione controllo di tipo tempo, ho sempre preferito usare conversioni implicite per eseguire questa. L'unico modo che conosco per fare questo comporta due righe di codice e introduce un'altra variabile nel campo di applicazione. Di seguito è riportato un esempio:

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

Poiché il compilatore sa che implementa MyType IMyType Suppongo che un cast implicito è meglio di un un esplicito dal momento che un cambiamento in seguito alla dichiarazione di MyType si tradurrà in un errore di compilazione invece di un InvalidCastException a runtime. Tuttavia, ho un po 'preferisco la semplicità della sintassi cast esplicito e visto spesso è usato in codice di altre persone.

La mia domanda è triplice:

  • Quale delle opzioni di cui sopra preferisci (e perché)?
  • C'è un modo migliore per fare questo?
  • Quali sono alcune buone pratiche per quanto riguarda l'esecuzione di cast espliciti quando cast impliciti sono possibili?
È stato utile?

Soluzione

Ecco una fase di compilazione verificato uno di linea:

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

Altri suggerimenti

Come una risposta a tutte le tre domande: Contare su cast impliciti come regola generale. Si programma contro l'interfaccia, non l'implementazione.

Per quanto riguarda l'ultimo, se proprio deve contare sulla programmazione contro un'implementazione (una specifica classe derivata) quindi assicurarsi che l'oggetto può essere lanciato il tipo prima di tentare di fare qualsiasi cosa con esso. Qualcosa di simile a questo:

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

Se non si è sicuri che l'oggetto è un'istanza dell'interfaccia poi fare un controllo da / null. Di solito si sta tornando un'interfaccia da un metodo / funzione di chiamata in questo caso è sufficiente memorizzare in una variabile senza un cast (anche se l'assegno nulla può essere necessario).

Io di solito piace come:

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... */ }

     }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top