2009-03-26 1 views
19

Я был бы уверен, что в этом вопросе рассматривается то, что было бы затронуто в предыдущем вопросе, но я не смог его найти.Преобразование списка базового типа в список унаследованного типа

В классе C# существует метод, который принимает в качестве параметра общий список базового класса. Мне нужно передать список унаследованного класса и точно не знаю, как это сделать. Я получаю ошибку в моих попытках. Ниже приведен пример кода для иллюстрации этого:

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 

Примечание: Вот мой последний рабочий метод в качестве ссылки. Я получил еще лучшее решение моей проблемы, но технически это был не ответ на вопрос, так как мой вопрос был сформулирован неправильно.

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

Это тот же ответ, который я вам дал ... –

+0

И это технически ответ на то, что вы изначально задали, а также! :) –

ответ

29

Если у вас есть LINQ доступные вы можете сделать

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

Я не думаю, что у меня есть linq, но он все равно работал. Большое вам спасибо за ваш быстрый ответ. – stephenbayer

+0

Возможная проблема - необходимо ли MethodC изменить список, чтобы эти изменения были видны вне MethodC? –

+0

Рад, что это сработало!Единственная причина, по которой я считаю, что у вас есть доступные методы расширения LINQ, было использование ToList в вашем примере. –

4

Вы обращаетесь отсутствие ковариации в текущей C# версии. Вот один из способов сделать это:

listOfB.Cast<A>(); 
+0

Это даст вам IEnumerable , а не список . – tvanfosson

+0

@tvanfosson - Хороший улов! –

9

Вы не можете этого сделать. Чтобы понять, почему это не допустимо, представьте, что произойдет, если Add был вызван на List<Derived> после того, как он был перенесен на List<Base>.

Кроме того, ответы, подразумевающие, что C# 4.0 будут разными, являются неправильными. Список никогда не будет изменен, чтобы вы могли это сделать. Только IEnumerable будет - потому что он не позволяет добавлять предметы в коллекцию.

Обновление: причина, по которой он работает в решении, для которого вы пошли, заключается в том, что вы больше не проходите мимо того же списка. Вы создаете совершенно новый список, который является копией оригинала. Вот почему я спросил об изменении списка; если MethodC вносит изменения в количество элементов в списке, эти изменения будут внесены в копию, а не в исходный список.

Я думаю, что это идеальное решение для вас следующим образом:

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); 
    } 
} 

Обратите внимание, как, с этим решением, вы можете передать List<B> непосредственно MethodC без необходимости делать это странное преобразование на него первым. Таким образом, нет ненужного копирования.

Причина этого в том, что мы сказали MethodC, чтобы принять список всего, что происходит от A, вместо того, чтобы настаивать на том, что это должен быть список A.

+0

Я не думаю, что это правда, он отлично работает. Мой вызов метода работает с петлями через коллекцию и действует на абстрактные (переопределяющие) методы и свойства. Я использовал код выше в предыдущем ответе, и он отлично работает. проект представляет собой .NET 2.0 с CSC.exe (C#) 3.0 в качестве компилятора. – stephenbayer

+0

См. Обновление выше. –

+0

Я предполагаю, что вам трудно заставить это работать? :) –

3

Вот ответ, который исключает любые объекты из вашего списка неправильного типа. Это гораздо более безопасный способ, на мой взгляд:

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

Метод OfType исключает элементы неправильного производного класса, где, как Cast сгенерирует ошибку.