2011-12-06 22 views
8

Necesito algún consejo/ayuda sobre esto, ya no puedo ver la madera de los árboles.C# genéricos de lanzamiento (¿covarianza y contravarianza?)

Es una serie sencilla de clases que implementan algunas interfaces utilizando genéricos.

entonces estoy tratando de emitir los tipos de hormigón, por ejemplo:

MyGenericObject<SomeObject> _obj; 

IMyGenericObject<ISomeObject> _genObj = (IMyGenericObject<ISomeObject>)_obj; 

// no válida fundido

He leído algunos artículos sobre covarianza y contravarianza pero no demasiado claro por qué este wouldn' ser posible, o cómo esquivarlo?


Por lo tanto, en este ejemplo:

public interface IMyObject<in T> where T : IBaseObject 
{ 
    T Activity { get; set; } 
} 

no funcionaría ...


.... porque, no se puede obtener y establecer la propiedad Actividad .

En este ejemplo, que tenía que hacer:

public interface IMyObject<out T> where T : IBaseObject 
    { 
     T Activity { get; } 
    } 

esperanza de que ayude a alguien, y gracias a todos por la ayuda!

+0

Por favor, muestre la definición de su interfaz –

Respuesta

9

Solo puede hacer eso si declara que la interfaz tiene un parámetro covariante (out). Solo puede hacer eso si el parámetro se usa de forma coherente.

Por ejemplo, si la interfaz IMyGenericObject<T> tiene un método tomando un parámetro T, esto le impide declarar el parámetro como covariante. Por el contrario, si hay un método que devuelve T, eso le impide declarar el parámetro como contravariante.

EDITAR

En respuesta a su comentario sobre la respuesta de SLaks, me siento tentado a repetir todo lo que Eric Lippert ha escrito nunca en co- y contravarianza. Ver http://blogs.msdn.com/b/ericlippert/archive/tags/Covariance+and+Contravariance/ y también sus respuestas en SO (más recientemente https://stackoverflow.com/a/8380213/385844)

En resumen:

no se puede echar IList<string> a IList<object> porque es legal para aprobar una FileInfo a un IList<object>, pero no es legal para aprobar a un IList<string>.

No se puede emitir un IList<object> a un IList<string>, ya sea legal para recuperar un elemento de una IList<string> y asignarlo a una cadena de referencia, sino una IList<object> puede contener un FileInfo, que no se puede asignar a una cadena referencia.

EDIT 2

Has solicitado que consejos, también es posible dividir las interfaces en co- y partes contravariant. Para continuar con el ejemplo de la lista, usted podría tener estas interfaces

public interface ICovariantList<out T> 
{ 
    T this[int index] { get; } 
    //... 
} 

public interface IContravariantList<in T> 
{ 
    T this[int index] { set; } 
    void Add(T item); 
    //... 
} 

public class SomeList<T> : ICovariantList<T>, IContravariantList<T> 
{ 
    //... 
} 

Esto le permite utilizar la clase covariantly o contravariantly, dependiendo del contexto.

+0

ordenados, ¡gracias por la ayuda! – sambomartin

+0

@sambomartin eres bienvenido. Algunos consejos más en EDITAR 2. – phoog

+0

gracias, como que lo sospeche, aunque al final no necesité el colocador ... ¡pero lo sé para la próxima! – sambomartin

4

Debe declarar que la interfaz tiene un parámetro genérico covariante (out).

+2

covariant is 'out'; contravariante es 'in'. Mnemónico: "o" para covariante y fuera; "n" para contravariante y en. – phoog

+0

bien, gracias. El siguiente problema que tengo es que el compilador informa: "Error 1 Varianza no válida: el parámetro de tipo 'xxx debe ser invariablemente válido en' xxx es covariante '. Por lo que he leído, necesito que la interfaz sea solo de lectura/invariante. Tengo una propiedad de IMyGenericInterface SomeObject SomeObjectInstance {get; set;} ¿Alguna idea? – sambomartin

+0

@sambomartin: Debes entender cómo funciona la varianza. Una propiedad variante escribible es intrínsecamente no segura para tipos. – SLaks

Cuestiones relacionadas