2012-09-18 12 views
22

Perché la proprietà ottiene l'errore mentre il metodo può essere compilato?Scostamento non valido: il parametro di tipo 'T' deve essere controvaramente valido su 'UserQuery.IItem <T> .ItemList'. 'T' è covariante

public interface IFoo {} 
public interface IBar<out T> where T : IFoo {} 

public interface IItem<out T> where T: IFoo 
{ 
    // IEnumerable<IBar<T>> GetList(); // works 
    IEnumerable<IBar<T>> ItemList { get; set; } // Error! 
} 

Errore:

Invalid variance: The type parameter 'T' must be contravariantly valid on 'UserQuery.IItem<T>.ItemList'. 'T' is covariant.

+0

Possibile duplicato di [T deve essere controvariante valido] (https://stackoverflow.com/questions/5041664/t-must-be-contravariantly-valid) –

risposta

27

È possibile ottenere l'errore del compilatore, perché hai un getter di proprietà (get) e un setter (set). Il getter della proprietà ha il T in uscita in modo che out funzioni, ma il setter della proprietà avrà il T nel suo input, quindi sarebbe necessario il modificatore in.

Perché hai out su T è necessario rimuovere il setter e sarà la compilazione:

public interface IItem<out T> where T : IFoo 
{ 
    // IEnumerable<IBar<T>> GetList(); // works 
    IEnumerable<IBar<T>> ItemList { get; } // also works 
} 

Se il T è un argomento generico in quindi il seguente dovrebbe funzionare:

public interface IItem<in T> where T : IFoo 
{ 
    IEnumerable<IBar<T>> ItemList { set; } 
} 

Ma non è possibile avere entrambi (out,in) allo stesso tempo in modo da non poter avere una proprietà co/controvariante con un getter e un setter.

+2

Non lo capisco. Hai messo in relazione, in per ottenere, impostare. Perché non posso usare out, poiché out significa solo "questo tipo o qualsiasi tipo derivato". Se B deriva da A, allora perché non posso passare B a qualsiasi proprietà dell'interfaccia che richiede un out A, poiché B sarà chiamato come se fosse un A comunque. Qual è il problema e cosa c'entra con tutto ciò? in dice "questo tipo o qualsiasi tipo di base". Non voglio che, poiché mi aspetto di usare almeno il set di comportamento di A, il passaggio di una "a" non lo taglierà. Quindi non vorrei "in" ... ma voglio essere in grado di impostare B in out A. – rism

2

Il setter non è consentito, in quanto se fosse si sarebbe in grado di fare questo:

public interface ISubFoo : IFoo { } 

IItem<ISubFoo> item = //whatever 
item.ItemList = new List<IBar<IFoo>>>(); 

che non è di tipo sicuro.

Problemi correlati