Подтвердить что ты не робот

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

У меня есть

List<InputField> 

но мне нужен

List<IDataField>  

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

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

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

Этот список исходит из запроса Linq-to-Sql:

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

Ответ 1

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

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

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

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

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

Ответ 2

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

Ответ 4

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

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>();

Ответ 5

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

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

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

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

Ответ 6

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

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

Ответ 7

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

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

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

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

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

Ответ 8

У меня есть следующая строка

 var str = "2 4 7 8 10";

когда я произнесу как следовать

var numbersInt2 = numbers.Split(' ')
                .ToList().Cast<int>().ToList();

возвращает исключение, но

System.InvalidCastException: 'Указанное приведение недействительно.'

при использовании следующего

var numbersInt = numbers.Split(' ')
                .ToList().ConvertAll(int.Parse);

это работает.