2013-03-24 11 views
7

Próbuję utworzyć metodę, która zwraca listę dowolnego typu użytkownik chce. Aby to zrobić, używam generycznych, których nie znam zbyt dobrze, więc to pytanie może być oczywiste. Problemem jest to, że ten kod nie działa i generuje komunikat o błędzie Cannot convert type Systems.Collections.Generic.List<CatalogueLibrary.Categories.Brand> to Systems.Collection.Generic.List<T>Może używać IList, ale nie Lista w ogólnej metodzie

private List<T> ConvertToList<T>(Category cat) 
{    
    switch (cat) 
    { 
     case Category.Brands: 
      return (List<T>)collection.Brands.ToList<Brand>(); 

    } 
    ... 
} 

Ale jeśli mogę użyć IList zamiast istnieją żadne błędy.

private IList<T> ConvertToList<T>(Category cat) 
{    
    switch (cat) 
    { 
     case Category.Brands: 
      return (IList<T>)collection.Brands.ToList<Brand>(); 

    } 
    ... 
} 

Dlaczego mogę używać IList, ale nie List w tym przypadku? collection.Brands zwraca typ BrandCollection z biblioteki innej firmy, więc nie wiem, jak to się stało. Czy to możliwe, że BrandCollection może pochodzić z IList (po prostu zgaduje, że tak) i dlatego można go przekonwertować, ale nie na normalną listę?

+0

Powinieneś umieścić ograniczenia typu tam na oficera! Nie możesz tak po prostu chodzić, rzucając coś niedobrze. – antonijn

+3

Czy jesteś pewien, że twój drugi przykład nie jest zbiorem "return (IList ). Brands.ToList ();"? – Matthew

+0

Zamierzałem się przyjrzeć, jak to zadziałało. Jestem trochę nowy dla leków generycznych, więc pomyślałem, że zostawię to na później, na wypadek, gdyby złamał coś innego: D Czy przymus byłby "gdzie T: Brand" (i inne kategorie)? – XSL

Odpowiedz

9

Ponieważ nie ma ograniczeń na T, można go przekonwertować na object w czasie kompilacji. Przesyłanie do typów interfejsów nie jest sprawdzane przez kompilator, ponieważ teoretycznie można utworzyć nową klasę, która implementuje IList<object> i dziedziczy List<Brand>. Jednak rzutowanie na List<T> zakończy się niepowodzeniem, ponieważ wiadomo, że nie może istnieć klasa, która dziedziczy zarówno List<object>, jak i . Jednak w twoim przypadku wiesz, co to jest typ T za pośrednictwem oświadczenia switch i chcesz wymusić rzutowanie. Aby to zrobić, oddanych przez object pierwszy następująco:

private List<T> ConvertToList<T>(Category cat) 
{    
    switch (cat) 
    { 
     case Category.Brands: 
      return (List<T>)(object)collection.Brands.ToList<Brand>(); 
    } 
} 

Większym problemem projektowania tutaj jest jednak to, że leki generyczne nie są najlepszym wyborem, gdy masz dyskretnych listę znanych typów dla T. Generics są lepsze, gdy T mogą być dowolne, lub być ograniczone do typu podstawowego lub interfejsu. Tutaj, byłbyś lepiej po prostu pisać oddzielny sposób dla każdej gałęzi instrukcji switch:

private List<Brand> ConvertToBrandList() 
{ 
    return collection.Brands.ToList<Brand>(); 
} 

Bez tego masz bardzo mało typu bezpieczeństwa. Co jeśli ktoś zadzwoni na twoją metodę z ConvertToList<int>(Category.Brands)?

+0

Dzięki za wyjaśnienie. Mimo że metoda "obiektu" zadziałała, wybiorę metodę indywidualną. Nie byłbym w stanie ograniczyć się do "Marki", ponieważ właśnie dowiedziałem się, że jest to zamknięta klasa. – XSL

+0

+1. Myślę, że prawdziwym powodem jest odwołanie do C# 6.2.4: "Konwersje jawne referencyjne są ...\t Od * dowolnego typu klasy S * do * dowolnego typu interfejsu T *, pod warunkiem, że S nie jest zapieczętowany i pod warunkiem, że S nie implementuje T. " –

Powiązane problemy