Преобразование списка базового типа в список наследуемого типа - PullRequest
19 голосов
/ 26 марта 2009

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

В классе 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;
        }

Ответы [ 4 ]

30 голосов
/ 26 марта 2009

Если у вас есть linq, вы можете сделать

var ListOfA = ListOfB.Cast<A>().ToList();
9 голосов
/ 26 марта 2009

Вы не можете этого сделать. Чтобы понять, почему это не разрешено, представьте, что произойдет, если 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.

4 голосов
/ 26 марта 2009

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

listOfB.Cast<A>();
3 голосов
/ 27 ноября 2014

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

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

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

...