Ответ 1
Если у вас есть доступ к linq, вы можете сделать
var ListOfA = ListOfB.Cast<A>().ToList();
Я был бы уверен, что в этом вопросе рассматривается то, что было бы затронуто в предыдущем вопросе, но я не смог его найти.
В классе С# есть метод, который принимает в качестве параметра общий список базового класса. Мне нужно передать список унаследованного класса и точно не знаю, как это сделать. Я получаю ошибку в моих попытках. Ниже приведен пример кода для иллюстрации:
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;
}
Если у вас есть доступ к linq, вы можете сделать
var ListOfA = ListOfB.Cast<A>().ToList();
Вы не можете этого сделать. Чтобы понять, почему это недопустимо, представьте, что произойдет, если Add
был вызван на List<Derived>
после того, как он был перенесен в List<Base>
.
Кроме того, ответы, подразумевающие, что С# 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
.
Вы рассматриваете недостаток ковариации в текущей версии С#. Вот один из способов сделать это:
listOfB.Cast<A>();
Вот ответ, который исключает любые объекты из вашего списка неправильного типа. На мой взгляд, это намного безопаснее:
List<A> ListOfA = ListOfB.OfType<A>().ToList();
Метод OfType будет исключать элементы неправильного производного класса, где, когда Cast будет вызывать ошибку.