2009-03-26 13 views
19

Byłbym pewien, że to pytanie dotyczy czegoś, co zostało poruszone w poprzednim pytaniu, ale nie mogłem go znaleźć.Konwertowanie listy typów bazowych na listę dziedziczonych typów

Istnieje metoda w klasie C#, która jako parametr przyjmuje ogólną listę klasy bazowej. Muszę przekazać listę odziedziczonej klasy i nie wiem dokładnie, jak to zrobić. Otrzymuję błąd w moich próbach. Poniżej znajduje się przykładowy kod zilustrowany:

public class A 
{ 
    public static void MethodC(List<A>) 
    { 
     // Do Something here with the list 
    } 
} 
public Class B : A 
{ 
    // B inherits from A, A is the Base Class 
} 

// Code utilizing the above method 
List<B> listOfB = new List<B>(); 
A.MethodC((List<A>) listOfB); // Error: this does not work 
A.MethodC(listOfB.ToList<typeof(A)>()); // Error: this does not work 
A.MethodC(listOfB.ConvertAll<A>(typeof(A))); // Error: this does not work 
// how can I accomplish this? It should be possible I would think 

Uwaga: Oto moja ostatnia metoda robocza jako odniesienie. Mam jeszcze lepsze rozwiązanie mojego problemu, ale technicznie nie była to odpowiedź na to pytanie, ponieważ moje pytanie zostało sformułowane niepoprawnie.

public static DataTable 
    ObjectCollectionToDataTable<GLIST> 
     (List<GLIST> ObjectCollection) where GLIST 
       : BaseBusinessObject 
     { 
      DataTable ret = null; 

      if (ObjectCollection != null) 
      { 
       foreach (var b in ObjectCollection) 
       { 

        DataTable dt = b.ToDataTable(); 
        if (ret == null) 
         ret = dt.Clone(); 
        if (dt.Rows.Count > 0) 
         ret.Rows.Add(dt.Rows[0].ItemArray); 
       } 
      } 

      return ret; 
     } 
+0

To ta sama odpowiedź, którą ci dałem ... –

+0

I technicznie jest to odpowiedź na to, co pierwotnie zadałeś! :) –

Odpowiedz

29

Jeśli masz LINQ dostępne można zrobić

var ListOfA = ListOfB.Cast<A>().ToList(); 
+0

Nie sądzę, że mam linq, ale i tak zadziałało. bardzo dziękuję za szybką odpowiedź. – stephenbayer

+0

Możliwy problem - czy metoda MethodC musi zmodyfikować listę, aby te zmiany były widoczne poza MethodC? –

+0

Cieszę się, że zadziałało!Jedynym powodem, dla którego uważam, że masz dostępne metody rozszerzenia LINQ, było użycie ToList w twoim przykładzie. –

9

Nie możesz tego zrobić. Aby zrozumieć, dlaczego nie jest to dozwolone, wyobraź sobie, co by się stało, gdyby Add został wywołany na List<Derived> po jego przesłaniu do List<Base>.

Ponadto, odpowiedzi sugerujące, że C# 4.0 będą różne, są błędne. Lista nigdy nie zostanie zmodyfikowana, abyś mógł to zrobić. Tylko IEnumerable będzie - ponieważ nie pozwala na dodawanie elementów do kolekcji.

Aktualizacja: Przyczyną tego, że pracuje w roztworze odeszłaś na to, bo już nie jesteś przejazdem na tej samej liście. Tworzysz zupełnie nową listę, która jest kopią oryginału. Dlatego poprosiłem o modyfikację listy; jeśli MethodC wprowadza zmiany w liczbie pozycji na liście, zmiany te zostaną wprowadzone do kopii, a nie do oryginalnej listy.

Myślę, że idealnym rozwiązaniem dla Ciebie jest następująca:

public abstract class A 
{ 
    public void MethodC<TItem>(List<TItem> list) where TItem : A 
    { 
     foreach (var item in list) 
      item.CanBeCalled(); 
    } 

    public abstract void CanBeCalled(); 
} 

public class B : A 
{ 
    public override void CanBeCalled() 
    { 
     Console.WriteLine("Calling into B"); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<B> listOfB = new List<B>(); 

     A a = new B(); 

     a.MethodC(listOfB); 
    } 
} 

Wskazówki, jak z tego rozwiązania, można przejść bezpośrednio do MethodCList<B> bez konieczności zrobić to dziwne konwersję na nim w pierwszej kolejności. Bez zbędnego kopiowania.

Powodem tego działania jest, ponieważ powiedzieliśmy MethodC, aby zaakceptować listę wszystkiego, co pochodzi od A, zamiast nalegać, że musi to być lista A.

+0

Nie sądzę, że to prawda, działa dobrze. Moja metoda wywołuje pętle robocze poprzez kolekcję i działa na abstrakcyjnych (nadpisujących) metodach i właściwościach. Użyłem powyższego kodu w poprzedniej odpowiedzi i działa świetnie. projektem jest .NET 2.0 z CSC.exe (C#) 3.0 jako kompilatorem. – stephenbayer

+0

Zobacz aktualizację powyżej. –

+0

Zgaduję, że masz trudności z uruchomieniem tej funkcji? :) –

3

Oto odpowiedź, która wykluczy jakiekolwiek obiekty z listy niewłaściwego typu. Jest to znacznie bezpieczniejszy sposób moim zdaniem:

List<A> ListOfA = ListOfB.OfType<A>().ToList(); 

Sposób OfType wykluczy przedmioty klasy źle pochodzącego gdzie jako Obsada wygeneruje błąd.

Powiązane problemy