2010-10-31 13 views
6

Deve esserci qualcosa di fondamentale su interfacce/generici che non ho ancora imparato. Spero di impararlo ora.Perché un elenco di interfacce non può utilizzare un tipo di implementazione?

Ecco lo scenario:

ho questa interfaccia e classe:

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

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

Se creo un metodo come questo si compila bene:

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

nota che io sono restituire un oggetto che implementa l'interfaccia.

Ora, se posso aggiungere alla classe RandomTest un metodo che restituisce la lista allora non funziona più:

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

Quindi, la mia ipotesi è che i generici non possono capirlo, ma perché?

C'è un modo per aggirare questo? Che cosa fate quando il valore di ritorno del metodo di cui sopra è bloccata perché si implementa un'interfaccia simile a questo:

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

C'è qualche speranza? Cosa faresti?

risposta

9

Il motivo è che List<RealValue> è un tipo specifico, che non eredita List<IInterface>, quindi non può essere convertito.

Tuttavia, in .NET 4.0 siete fortunati. L'interfaccia IEnumerable<out T> specifica che T può essere la classe, o di una classe base, in modo da poter cambiare il metodo di:

IEnumerable<IInterface> GetRealValues(); 

su .NET 4.0. Si noti che questo funziona solo perché IEnumerable ha la parola chiave out specificata nel parametro del modello.

Il out parola chiave significa due cose:

  1. Il tipo di fronte al quale si mette la parola out può essere utilizzato solo per i tipi che vanno fuori della classe. Quindi, public T MyMethod() è consentito, ma public void MyMethod(T myParam) non è consentito, perché questo va nella classe;

  2. A causa di questa limitazione, .NET sa che T può essere incassato a tutto ciò che eredita da T. A causa della restrizione, si garantisce che si tratti di un'operazione sicura.

+0

Questo sembra bello. Dovrò scavare di più per capire cosa significa 'out' per un parametro di tipo generico. Ad ogni modo, ho provato e ha funzionato. – Vaccano

+0

Espandi la risposta con qualche informazione in più sulla parola chiave 'out'. –

+0

Dolce! Grazie per la risposta espansa! – Vaccano

1

A List<RealValue> non può essere utilizzato al posto di List<IInterface>. Se era consentito, il chiamante sarebbe in grado di aggiungere un numero IInterface all'elenco restituito che è di un tipo diverso da RealValue.

3

Si noti che se è possibile convertire List<RealValue> a List<IInterface> è possibile chiamare .Add(anyObjectImplementingIInterface) che non può funzionare.

È tuttavia possibile utilizzare .Cast<IInterface>().ToList().

Problemi correlati