Список ролях <T> до списку <Інтерфейс>


Відповіді:


250

Ви не можете кинути його (зберігаючи кількість посилань ідентичність) - це було б небезпечно. Наприклад:

public interface IFruit {}

public class Apple : IFruit {}
public class Banana : IFruit {}

...

List<Apple> apples = new List<Apple>();
List<IFruit> fruit = apples; // Fortunately not allowed
fruit.Add(new Banana());

// Eek - it's a banana!
Apple apple = apples[0];

Тепер ви можете конвертувати List<Apple>в IEnumerable<IFruit>в .NET 4 / C # 4 з - за ковариации, але якщо ви хочете List<IFruit>ви повинні створити новий список. Наприклад:

// In .NET 4, using the covariance of IEnumerable<T>
List<IFruit> fruit = apples.ToList<IFruit>();

// In .NET 3.5
List<IFruit> fruit = apples.Cast<IFruit>().ToList();

Але це не те саме, що кастинг оригінального списку - адже зараз є два окремих списки. Це безпечно, але потрібно розуміти, що зміни, внесені до одного списку , не будуть помічені в іншому списку. ( Зрозуміло, побачать зміни об'єктів , на які посилаються списки.)


6
наче вони "все ще в будівлі"!
Андрас Золтан

1
Яка різниця між виконанням списку коваріації та новим списком <IFruit> (); то передбачити над початковим списком і додати кожен елемент до списку IFruit? У передбачуваному відношенні ... посилання на об'єкт було б однаковим, правильно? Отже ... якщо це правда, особисто для мене мало сенсу, що ви не можете просто подати весь список. ?
Роберт Ноак

3
@RobertNoack: Що ви маєте на увазі під "посиланням на об'єкт"? Посилання на об'єкт кожного елемента є однаковим, але це не те саме, що кастинг самого посилання на список. Припустимо, ви можете подати посилання, щоб у вас було посилання типу компіляції, List<IFruit>яке насправді було посиланням на a List<Apple>. Що ви очікуєте, що це станеться, якщо ви додасте Bananaпосилання на це List<IFruit>?
Джон Скіт

1
Ой. Я думаю, що мені потрібно навчитися читати. Я подумав, що в оригінальній відповіді сказано, що об'єкти у списку будуть глибоко скопійовані та відтворені, що не мало для мене сенсу. Але я чітко пропустив ту частину, де створюється лише новий список з тими ж об’єктами.
Роберт Ноак

2
@ TrươngQuốcKhánh: Я поняття не маю, як виглядає будь-який ваш код, чи є у вас usingдиректива System.Linq, або як ви намагаєтесь її закликати, я не впевнений, як ви очікуєте від мене допомоги. Я пропоную вам провести більше досліджень, і якщо ви все-таки застрягли, ви ставите питання з мінімальним відтворюваним прикладом .
Джон Скіт

6

Ітератор Cast і .ToList ():

List<IDic> casted = input.Cast<IDic>().ToList() зробить трюк.

Спочатку я казав, що коваріація спрацює - але, як справедливо зазначив Джон; ні, не буде!

І спочатку я теж тупо припинив ToList()дзвінок


Castповертає IEnumerable<T>, а не List<T>- і ні, коваріація не дозволить цю конверсію, оскільки це було б небезпечно - дивіться мою відповідь.
Джон Скіт

На сторінці, на яку ви посилаєтесь: "Тільки типи інтерфейсів і делегат можуть мати параметри типу варіанту"
Джон Скіт,

@Jon - я зрозумів, що цього не ToList()було, перш ніж прочитати ваш коментар; але так, як ви показали, звичайно, коваріація не буде працювати! До!
Андрас Золтан

Правильно. Коваріація все ще може допомогти, оскільки це означає, що вам не потрібен Castдзвінок у .NET 4, якщо ви вкажете аргумент типу для ToList.
Джон Скіт

5

У мене теж була ця проблема, і прочитавши відповідь Джона Скіта, я змінив свій код від використання List<T>до використання IEnumerable<T>. Хоча це не дає відповіді на питання оригінальний OP по Як я можу кинути , List<Client>щобList<IDic> , це уникнути необхідності робити це , і , таким чином , може бути корисним для інших людей , які стикаються з цією проблемою. Звичайно, це передбачає, що код, який вимагає використання, List<IDic>знаходиться під вашим контролем.

Наприклад:

public void ProcessIDic(IEnumerable<IDic> sequence)
{
   // Implementation
}

Замість:

public void ProcessIDic(List<IDic> list)
{
   // Implementation
}

3

Якщо ви можете використовувати LINQ, ви можете це зробити ...

List<Client> clientList = new List<Client>();
List<IDic> list = clientList.Select(c => (IDic)c).ToList();


0

Це можливо лише шляхом створення нових List<IDic>та передачі всіх елементів.


Будь-який коментар навіщо спростовується, оскільки загальний зміст такий самий, як і всі інші відповіді?
Пьотр Августик

Моя здогадка, ви б зголосилися, тому що ви сказали, що можна створити лише новий список, але інші опублікували навпаки ... не мій downvote, хоча)
musefan

Добре, вони створюють нові списки, але не з новим оператором, що не змінює того, що вони роблять.
Пьотр Августик

0

У .Net 3.5 ви можете зробити наступне:

List<ISomeInterface> interfaceList = new List<ISomeInterface>(list.Cast<ISomeInterface>());

Конструктор List у цьому випадку приймає IEnumerable.
Список, хоча конвертований лише в IEnumerable. Навіть незважаючи на те, що myObj може бути конвертований в ISomeInterface, тип IEnumerable не перетворюється на IEnumerable.


Питання це робить копію списку, більшу частину часу ви хочете , щоб робити операції на первинному списку
котиться
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.