2009-02-02 7 views
20

У меня естьКак эффективно использовать список <T>?

List<InputField> 

, но мне нужно

List<IDataField> 

Есть ли способ, чтобы бросить это в C#? Или использовать Linq для получения такого же результата?

У меня есть два класса, которые реализуют один и тот же интерфейс:

interface IDataField { } 
class InputField : IDataField { } 
class PurchaseField : IDataField { } 

Этот список поставляется из запроса Linq-на-Sql:

List<InputField> list = (from i .... select i).ToList(); 
+0

Хм, Maby это умнее, чтобы выяснить, почему вам нужен список InputField вместо список IDataField в первую очередь? Или это действительно необходимо? –

+0

Я думаю, что это необходимо. InputField и PurchaseField - это две разные вещи, которые имеют две общие черты. IDataField выражают это. У меня есть сложная логика, которая работает только с IDataField. – bentford

+0

Примечание для всех: это действительно хорошие ответы! Спасибо за быстрый ответ!!! – bentford

ответ

36

< И .OfType Т > и .Cast < Т > будет возвращать список T, но смысл этих двух методов отличается.

list.OfType Фильтры Исходный список и возвращает все элементы, имеющие тип T, и пропускает те, которые не относятся к этому типу.

list.Cast отличает все элементы в исходном списке, чтобы ввести T, и выдает исключение для элементов, которые нельзя отнести к этому типу.

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

List<InputField> list = (from i .... select i).Cast<IDataField>.ToList(); 
+0

Черт - избил меня на 35 секунд. Upvoted - это правильный ответ, поскольку OP ищет отливку. –

+0

Я принял этот ответ, потому что я действительно искал бросок. Спасибо всем. – bentford

11
List<InputField> raw = (from i .... select i).ToList(); 
List<IDataField> result = raw.OfType<IDataField>().ToList(); 
1

Я не знаю, что прямой эффект будет иметь желаемый эффект. Редкие несколько раз я сделал это, это обычно что-то вроде:

List<InputField> list = ..... 
List<IDataField> list2 = new (List<IDataField>((IDataField[])list.ToArray())); 
4

Поскольку список исходит от

List<InputField> list = (from i .... select i).ToList(); 

не могли бы вы исправить «выбрать» я часть, чтобы вместо возвращения Вместо этого IDataField? Что-то вроде этого:

List<InputField> list = (from i .... select (IDataField)i).ToList(); 

Если это не работает, возможно, "Cast" расширение IEnumerable будет работать:

List<DataField> list2 = list.Cast<IDataField>(); 
+0

Фактически исправление «выбор» части запроса было бы лучшим. В противном случае посмотрите на ответ Хелен Тоомик на разницу между OfType и Cast ... –

6

Вы также можете использовать List.ConvertAll.

Документация: http://msdn.microsoft.com/en-us/library/73fe8cwf.aspx

Пример:

List<IDataField> newList = oldList.ConvertAll(i => i as IDataField); 
+2

Только то, что я собирался сказать. Обратите внимание, что в C# 2.0 вам нужно будет указать общий тип явно, но в C# 3.0 (как указано выше) это выведено. –

3

Только в случае, если: У меня мало C# опыт, но если это общая конструкция означает то же самое, что делает в Java, то вы должны создать целый новый список параметризованное супертипе.Другими словами, если каждый экземпляр Bangle также является экземпляром Akthud, то не следует, что каждый List<Bangle> также является List<Akthud>.

Причина в том, что у вас могут быть две ссылки на это List<Bangle>. Если вторая ссылка отличает, а затем ссылается на нее как List<Akthud>, тогда ей разрешено добавлять Akthud, но теперь первая ссылка имеет List<Bangle>, члены которой не все Bangle s. Нарушение!

Это, как говорится, ответ Дэвида Б действительно должен делать то, что вы хотите, правильно, AFAICT. (Это похоже на операцию копирования.)

[И если я недопонимание семантики дженерик C#, я надеюсь, что кто-то поправляет меня в комментарии]

+0

Вы правы - дженерики в C# не являются ни ко-вариантами, ни контравариантными; что-то они исправляют на C# 4. Вот сообщение в MSDN, объясняющее это: http://msdn.microsoft.com/en-us/library/ms228359(VS.80).aspx –

+0

Хорошая ссылка. Я думаю, вы имели в виду это как иллюстрацию общей проблемы дисперсии, а не изменения C# 4 (я ничего там не видел). Просто быть чистым(?). Тем не менее, очень информативный. –

1

ConvertAll кажется лучшим решением, так как это Безразлично 't зависит от библиотеки Linq и короче и интуитивно понятнее.

Но оба они довольно обходные пути, чем решения. Оба они создают новую коллекцию с теми же данными. Должна быть поддержка общей ковариации в .net, то есть повышение уровня в общих коллекциях, что позволит вам сделать это естественным образом. Например:

List<IDataField> ls = (List<IDataField>)List<InputField> 

От моего поиска до сих пор, мой вывод, что .Net, как 3.5 не поддерживает эту функцию. Следовательно, мы должны обходиться обходными решениями.

Эти дискуссии по теме:

Смежные вопросы