2010-10-31 7 views
6

Debe haber algo fundamental acerca de las interfaces/genéricos que aún no he aprendido. Espero aprenderlo ahora¿Por qué una lista de interfaces no puede usar un tipo de implementación?

Aquí está el panorama:

tengo esta interfaz y clase:

public interface IInterface 
{ 
    string TestValue { get; set; } 
} 

public class RealValue: IInterface 
{ 
    public string TestValue { get; set; } 
} 

Si creo un método como este compila bien:

public class RandomTest: IMethodInterface 
{ 
    public IInterface GetRealValue() 
    { 
     RealValue realValue = new RealValue(); 
     return realValue; 
    } 
} 

en cuenta que estoy devolver un objeto que implementa la interfaz.

Ahora, si añado a la clase RandomTest un método que devuelve la lista, entonces ya no funciona:

public List<IInterface> GetRealValues() 
{ 
    List<RealValue> realValues = new List<RealValue>(); 
    return realValues; // ERROR Here <- says it can't convert to a List<IInterface> 
} 

lo tanto, mi opinión es que los genéricos no pueden resolver esto, pero ¿por qué?

¿Hay alguna forma de evitar esto? ¿Qué se hace cuando el valor de retorno del método anterior está bloqueado porque se está implementando una interfaz como esta:

public interface IMethodInterface 
{ 
    IInterface GetRealValue(); 
    List<IInterface> GetRealValues(); // Can't just convert the return types to a concrete 
             // class because I am implementing this. This 
             // interface is in a separate project that does not 
             // have the concrete classes. 
} 

¿Hay alguna esperanza? ¿Qué harías?

Respuesta

9

La razón de esto es que List<RealValue> es un tipo específico, que no hereda List<IInterface>, por lo que no se puede convertir.

Sin embargo, en .NET 4.0 está de enhorabuena. La interfaz IEnumerable<out T> especifica que T puede ser la clase, o una clase de base, por lo que puede cambiar su método a:

IEnumerable<IInterface> GetRealValues(); 

en .NET 4.0. Tenga en cuenta que esto solo funciona porque IEnumerable tiene la palabra clave out especificada en el parámetro de la plantilla.

La palabra clave out significa dos cosas:

  1. El tipo ante el cual se pone la palabra clave out sólo pueden emplearse para los tipos que salen de la clase. Entonces, public T MyMethod() está permitido, pero public void MyMethod(T myParam) no está permitido, porque esto va dentro de la clase;

  2. Debido a esta restricción, .NET sabe que T se puede conectar a todo lo que hereda de T. Debido a la restricción, se garantiza que es una operación segura.

+0

Esto se ve bien. Tendré que cavar más para entender qué significa 'out' para un param de tipo genérico. De cualquier manera, lo intenté y funcionó. – Vaccano

+0

Se amplió la respuesta con un poco más de información sobre la palabra clave 'out'. –

+0

¡Dulce! Gracias por la respuesta expandida! – Vaccano

1

A List<RealValue> no se puede utilizar en lugar de List<IInterface>. Si estaba permitido, la persona que llama podría Agregar un IInterface a la lista devuelta que es de un tipo distinto de RealValue.

3

Tenga en cuenta que si puede convertir List<RealValue> en List<IInterface> puede llamar al .Add(anyObjectImplementingIInterface) que no puede funcionar.

Puede, sin embargo, utilizar .Cast<IInterface>().ToList().

Cuestiones relacionadas