Список кастингов <T> - проблема ковариации/контравариантности
Учитывая следующие типы:
public interface IMyClass { }
public class MyClass : IMyClass { }
Интересно, как я могу преобразовать List<MyClass>
в List<IMyClass>
? Я не совсем ясно понимаю темы ковариации/контравариантности, но я понимаю, что из-за этого я просто не могу просто лишить Список.
Я мог бы придумать только это тривиальное решение; не хватает элегантности, тратя ресурсы:
...
public List<IMyClass> ConvertItems(List<MyClass> input)
{
var result = new List<IMyClass>(input.Count);
foreach (var item in input)
{
result.Add(item);
}
return result;
}
....
Как вы можете решить это более элегантно/результативно?
(Пожалуйста, помните, что мне нужно решение .NET 2.0, но для полноты я был бы рад увидеть более элегантные решения, использующие более новые версии фреймворков.)
Ответы
Ответ 1
Самый простой способ - использовать ConvertAll
:
List<IMyClass> converted = original.ConvertAll<IMyClass>(x => x);
Даже если вы используете .NET 2, вы можете использовать синтаксис лямбда, если используете VS2008 или выше. В противном случае всегда есть анонимные методы:
List<IMyClass> converted = original.ConvertAll<IMyClass>(
delegate (MyClass x) { return x; });
В .NET 3.5 вы можете использовать LINQ с Cast
, OfType
или даже просто Select
:
var converted = original.Cast<IMyClass>().ToList();
var converted = original.OfType<IMyClass>().ToList();
var converted = original.Select(x => (IMyClass) x).ToList();
В .NET 4.0 вы можете использовать ToList
напрямую без промежуточного литья из-за ковариации IEnumerable<T>
:
var converted = original.ToList<IMyClass>();
Ответ 2
Нужно ли быть списком? Решение IEnumerable
может быть более эффективным:
public IEnumerable<IMyClass> ConvertItems(List<MyClass> input)
{
foreach (var item in input)
{
yield return (IMyClass)item;
}
}
Ответ 3
(решение .NET 3.5)
List<MyClass> list = new List<MyClass> { ... };
List<IMyClass> converted = list.Cast<IMyClass>().ToList();