El acceso seguro y sencillo a los miembros explícitas de interfaces en C #
-
03-10-2019 - |
Pregunta
Cuando estoy trabajando con implementaciones de interfaces explícitas en C #, a menudo se hace necesario convertir un objeto a una de sus interfaces con el fin de acceder a un miembro de esa interfaz. Debido a la mayor fiabilidad y facilidad de mantenimiento proporcionada por la comprobación de tipos en tiempo de compilación, siempre he preferido utilizar conversiones implícitas para realizar esto. La única forma que conozco de hacer esto consiste en dos líneas de código e introduce otra variable en el ámbito de aplicación. A continuación se muestra un ejemplo:
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());
}
}
Debido a que el compilador sabe que implementa MyType
IMyType
Asumo que una conversión implícita es mejor que una explícita ya que un cambio posterior a la declaración de MyType
dará lugar a un error de compilación en lugar de un InvalidCastException
en tiempo de ejecución. Sin embargo, yo prefiero un poco la simplicidad de la sintaxis conversión explícita y, a menudo he visto que se usa en el código de otras personas.
Mi pregunta es triple:
- ¿Cuál de las opciones anteriores prefiere (y por qué)?
- ¿Hay una mejor manera de hacer esto?
- ¿Cuáles son algunas de las mejores prácticas con respecto a la realización de conversiones explícitas cuando son posibles conversiones implícitas?
Solución
Aquí es un tiempo de compilación comprueba un trazador de líneas:
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();
}
}
Otros consejos
Como respuesta a las tres preguntas: Se basan en conversiones implícitas como una regla general. Usted está programando en contra de la interfaz, no la implementación.
En cuanto a la última, si realmente debe confiar en la programación en contra de una aplicación (una clase derivada específica), entonces asegúrese de que el objeto se puede convertir el tipo antes de tratar de hacer nada con ella. Algo como esto:
var IMyType item3 = item as MyConcreteType;
if(item3 != null) {
item3.SayHello();
}
Si no está seguro de que el objeto es una instancia de la interfaz y luego hacer un cheque como / null. Por lo general, usted está volviendo una interfaz de una llamada a un método / función en cuyo caso que acaba de almacenar en una variable sin una conversión (aunque el cheque nulo aún puede ser necesario).
normalmente me gusta como:
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... */ }
}
}