Как эффективно создать Список <T>? - PullRequest
21 голосов
/ 02 февраля 2009

у меня есть

List<InputField> 

но мне нужно

List<IDataField>  

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

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

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

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

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

Ответы [ 7 ]

39 голосов
/ 02 февраля 2009

Оба .OfType и .Cast вернут список T, но значение этих двух методов различно.

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

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

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

List<InputField> list = (from i .... select i).Cast<IDataField>.ToList();
11 голосов
/ 02 февраля 2009
List<InputField> raw = (from i .... select i).ToList();
List<IDataField> result = raw.OfType<IDataField>().ToList();
7 голосов
/ 02 февраля 2009

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

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

Пример:

List<IDataField> newList = oldList.ConvertAll(i => i as IDataField);
5 голосов
/ 02 февраля 2009

Так как список приходит от

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

Не могли бы вы просто исправить часть "select i", чтобы вместо этого вернуть IDataField? Примерно так:

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

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

List<DataField> list2 = list.Cast<IDataField>();
3 голосов
/ 02 февраля 2009

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

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

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

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

1 голос
/ 04 марта 2009

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

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

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

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

Это обсуждения по теме:

1 голос
/ 02 февраля 2009

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

List<InputField> list = .....
List<IDataField> list2 = new (List<IDataField>((IDataField[])list.ToArray()));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...