2016-05-17 12 views
3

Wenn ich eine Root-SchnittstelleKonvertieren MyClass <TDescendent> zu MyClass <TAncestor>

public interface IEntity {} 

und eine abgeleitete Schnittstelle und Klassen haben:

public interface IFruit : IEntity {} 
public class Apple : IFruit {} 
public class Orange: IFruit {} 

Und irrelevant, aber vielleicht andere, die nicht implementieren IFruit :

public class Computer : IEntity {} 

Und eine generische Klasse dass nutzt all dies:

public class PurchasedItem<T> where T : IFruit 
{ 
    public int Qty{get;set;} 
    public T Item{get;set;} 
} 

Wie kann ich eine Liste deklarieren, die PurchasedItem<IFruit> und mit ihr arbeiten enthält?
Wenn ich dies tun:

var list = new List<PurchasedItem<IFruit>>(); 
list.Add(new PurchasedItem<Apple>()); 

... dann bekomme ich einen Fehler

Cannot convert from PurchasedItem<Apple> to PurchasedItem<IFruit>

+0

mit einer Schnittstelle erstellen und arbeiten, das * ist *, wie erklären Sie eine Liste, die 'PurchasedItem enthält ' und arbeite damit. Das bedeutet, dass Sie kein 'PurchasedItem ' darin speichern können, da dies kein' PurchasedItem 'ist. Dies wurde schon oft gefragt, ich werde sehen, ob ich eine gute Frage mit detaillierter Antwort finden kann. – hvd

+0

hast du versucht, zum Basistyp zu gießen? , Neu PurchasedItem ()). Cast

+0

@ Shachaf.Gortler Das gilt hier nicht, wäre aber nicht nützlich, auch wenn es galt. – hvd

Antwort

4

Sie können Kovarianz verwenden, wenn Sie für PurchaseItem<T>

public interface IEntity 
{ 
    int Id { get; set; } 
} 

public interface IFruit : IEntity 
{ 
} 

public class Apple : IFruit 
{ 
    public int Id { get; set; } 
} 

public interface IPurchaseItem<out T> where T : IFruit 
{ 
    int Qty { get; set; } 
    T Item { get; } // can't have setter here 
} 

public class PurchaseItem<T> : IPurchaseItem<T> 
    where T : IFruit 
{ 
    public int Qty { get; set; } 
    public T Item { get; set; } // setter here no problem 
} 


class Program 
{ 

    static void Main() 
    { 
     var applePurchaseItem = new PurchaseItem<Apple>(); 

     var fruitPurchaseItems = new List<IPurchaseItem<IFruit>>(); 

     fruitPurchaseItems.Add(applePurchaseItem); 
    } 
} 
+0

Dies funktioniert nicht für mich. Für "T Item" in "IPurchaseItem", bekomme ich, dass "der Typparameter T muss immer gültig sein ..." –

+0

Sie können keinen Setter für die Eigenschaft in der 'IPurchaseItem ' Schnittstelle haben, nur für die konkrete Implementierung (beachte das 'T Item {get;}') – Moho

+0

@Moho Danke dafür - es hilft sehr, und hat mich auch dazu gebracht viel zu lesen! – Geoff

2

Es kommt alles auf die Gestaltung des Klassenbaumes. Zum Beispiel finden Sie in dem folgenden Code:

public interface IEntity {} 

public interface IFruit : IEntity {} 

public class PurchasedItem 
{ 
    public int Qty { get; set; } 
} 

public class Apple : PurchasedItem, IFruit {} 
public class Orange: PurchasedItem, IFruit {} 

var list = new List<PurchasedItem>(); 
+0

Dies löst den Kompilierungsfehler, aber es löst nicht das Problem, sauber von der Liste auf ein IFruit zugreifen zu können. –

+0

John H, nichts hält Sie davon ab: var list = new Liste (); –

+0

Ich möchte nicht 'PurchasedItem' ->' Apple' ableiten, weil 'Apple' ein Geschäftsobjekt ist, das andere Nutzungen hat, ich will sie nicht mit' PurchasedItem' verwickeln - und hat bereits einen Vorgänger. – Geoff

Verwandte Themen