2012-01-26 14 views
10

Ponieważ nie wiem, jak nazywany jest mój problem, nie mogę zagwarantować, że nikt ostatnio nie zadał tego samego pytania.O generyce i dziedziczeniu (wybacz mój zły tytuł)

Zauważyłem jednak, że istnieje wiele wątków o podobnym tytule, ale nie wydają się one istotne dla mojego problemu.

Mam niestandardową klasę list, która implementuje generics.

class MyList<T> 
{ 
    public void add(T item) // adds an item to the list 
    { /* code */ } 
    public void add(MyList<T> list) // attaches an existing list to the end of the current one 
    { /* code */ } 
} 

Mam też klas:

class Apple : Fruit 

i

class Banana : Fruit 

Teraz przychodzi odpowiedni kod:

MyList<Fruit> fruitList = new MyList<Fruit>(); 
// fill fruitList 

fruitList.add(new Apple()); // works, of course 
fruitList.add(new Banana()); // works as well, of course 

MyList<Apple> appleList = new MyList<Apple>(); 
// fill appleList 

fruitList.add(appleList); // doesn't work. Why? 

Nawet appleList jest mylist (z Apple) i Apple to Fruit, VisualStudio nie akceptuje t MyList (Of Apple) jako argument, gdy pytamy MyList (Of Fruit).

Jednak gdybym miał zadeklarować listę takiego:

MyList<object> fruitList = new MyList<object>(); 

Wtedy wszystko znowu działa. Co dokładnie zrobiłem źle?

Odpowiedź byłaby bardzo cenna i dziękuję za poświęcenie czasu na przeczytanie, nawet bez odpowiedzi.

+1

Twojej wiadomości, główne słowa kluczowe dotyczące tego to kowariancja, sprzeczność i niezmienność. Tak, raczej trudno jest znaleźć, kiedy o tym nie wiesz. – delnan

+2

Powinieneś zaimplementować 'IList '. – SLaks

+0

Publiczne nazwy członków w .Net powinny być UpperCamelCase. – SLaks

Odpowiedz

8

Próbujesz użyć covariance.
. NET obsługuje tylko ogólne wariancje interfejsów, więc to nie zadziała.

Ponadto kowariancja ma sens tylko w przypadku typów niezmiennych.
Gdyby można było przekonwertować MyList<Apple> na MyList<Fruit>, można dodać do listy Orange, naruszając bezpieczeństwo typu.

Zamiast tego można zrobić metoda ogólna:

public void Add<U>(IList<U> list) where U : T 
3

myślę konstrukcja interfejsu IMyList powinno być:

public interface IMyList<T> : IEnumerable<T> 
{ 
    void Add(T item); 
    void AddRange(IEnumerable<T> itemList); 
} 

Wszystko działa zgodnie z oczekiwaniami. Czemu? Tylko dlatego, że w .NET 4.0 IEnumerable interfejs jest kowariantna w to typ parametru T, to co definicja wygląda następująco:

public interface IEnumerable<out T> : IEnumerable 

Prosta implementacja interfejsu IMyList (dekorator List):

public class MyList<T> : IMyList<T> 
{ 
    private readonly List<T> _list = new List<T>(); 

    #region Implementation of IMyList<in T> 

    public void Add(T item) 
    { 
     Console.WriteLine("Adding an item: {0}", item); 
     _list.Add(item); 
    } 

    public void AddRange(IEnumerable<T> itemList) 
    { 
     Console.WriteLine("Adding items!"); 
     _list.AddRange(itemList); 
    } 

    #endregion 

    #region Implementation of IEnumerable 

    public IEnumerator<T> GetEnumerator() 
    { 
     return _list.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    #endregion 
} 
+0

+1 za sugerowanie lepszego projektu – phoog

Powiązane problemy