Неможливо перетворити з IEnumerable <T> в ICollection <T>


91

Я визначив наступне:

public ICollection<Item> Items { get; set; }

Коли я запускаю цей код:

Items = _item.Get("001");

Я отримую таке повідомлення:

Error   3   
Cannot implicitly convert type 
'System.Collections.Generic.IEnumerable<Storage.Models.Item>' to 
'System.Collections.Generic.ICollection<Storage.Models.Item>'. 
An explicit conversion exists (are you missing a cast?)

Хтось може пояснити, що я роблю не так. Мене дуже бентежить різниця між Enumerable, Collections та використанням ToList ()

Додана інформація

Пізніше у своєму коді я маю таке:

for (var index = 0; index < Items.Count(); index++) 

Чи можу я визначити елементи як IEnumerable?


3
Чи можете ви надати більше інформації про тип _item та підпис Get (рядок) (зокрема тип повернення)?
Доктор Ендрю Бернетт-Томпсон

Чому б не змінити такий тип? public IEnumerable<Item> Items { get; set; }У вас є якісь особливі причини, щоб мати це як ICollection?
Майстер тіней - вухо для вас

IEnumerable <T> Get (рядок pk);
Samantha JT Star

Відповіді:


113

ICollection<T>успадковує від IEnumerable<T>так, щоб присвоїти результат

IEnumerable<T> Get(string pk)

до ICollection<T>цього є два шляхи.

// 1. You know that the referenced object implements `ICollection<T>`,
//    so you can use a cast
ICollection<T> c = (ICollection<T>)Get("pk");

// 2. The returned object can be any `IEnumerable<T>`, so you need to 
//    enumerate it and put it into something implementing `ICollection<T>`. 
//    The easiest is to use `ToList()`:
ICollection<T> c = Get("pk").ToList();

Другий варіант є більш гнучким, але має набагато більший вплив на продуктивність. Інший варіант - зберегти результат як, IEnumerable<T>якщо вам не потрібна додаткова функціональність, додана ICollection<T>інтерфейсом.

Додатковий коментар до продуктивності

Цикл у вас є

for (var index = 0; index < Items.Count(); index++)

працює на, IEnumerable<T>але неефективно; кожен виклик до Count()вимагає повного переліку всіх елементів. Або використовуйте колекцію та Countвластивість (без дужок), або перетворіть їх у цикл foreach:

foreach(var item in Items)

1
Яку додаткову функціональність додає ICollection?
Samantha JT Star

7
ICollection<T>ними можна маніпулювати (докладнішу інформацію див. у документі ), тоді як an IEnumerable<T>можна лише перерахувати.
Андерс Абель

Мені потрібно мати щось, де я можу запускати різні запити LINQ. Мені не потрібно додавати або робити щось подібне до списку. Чи означає це, що мені було б краще з ICollection.
Samantha JT Star

LINQ працює, IEnumerable<T>тому IEnumerable<T>цього достатньо.
Андерс Абель

31

Ви не можете перетворити безпосередньо з IEnumerable<T>на ICollection<T>. Ви можете скористатися ToListметодом, IEnumerable<T>щоб перетворити його наICollection<T>

someICollection = SomeIEnumerable.ToList();


Це працює для мене. Але чи є для мене гарною ідеєю конвертувати, чи я б краще використав IEnumerable як тип для Елементів. Якщо я використовую IEnumerable, чи роблю я це, щоб я міг робити більше дій щодо елементів, якщо це буде потрібно пізніше в моїй програмі?
Samantha JT Star

ICollection вже реалізує IEnumerable. Якщо ви стурбовані доступними діями, я думаю, вам слід піти на ICollection. Краще, якщо ви зможете прочитати фактичну різницю між ними, а потім вирішите, що насправді ви хочете використовувати
Харіс Хасан,

Я намагаюся зрозуміти, які переваги я мав би, якби використовував ToList (). Отримавши дані, я хотів би запускати запити LINQ щодо елементів.
Samantha JT Star

ToList () спрацює, але, як ви вже зазначили у своїх коментарях Get () повертає ICollection, так що насправді вам просто потрібно зробити приведення в ICollection <T>, або ще краще, змінити зворотний підпис Get to ICollection <T> . Використання ToList або ToArray буде працювати, але це також призведе до непотрібної операції створення пам’яті / копіювання
доктор Ендрю Бернетт-Томпсон,

Ви можете запускати запити LINQ як проти IEnumerable, так і проти ICollection. Переваги .. одне, яке я зараз знаю, - це Count ICollection, який підтримує рахунок і IEnumerable повертає результат, обчислюючи, скільки елементів у нього є. ICollection надає додатковий метод видалення, якого Ienumerables не робить
Haris Hasan

1

Очікуючи додаткової інформації з питання:

будь-ласка, надайте більше інформації про тип товару та підпис Get

Ви можете спробувати дві речі:

  • Щоб привести повернене значення _item.Get до (ICollection)
  • по-друге, використовувати _item.Get ("001"). ToArray () або _item.Get ("001"). ToList ()

Зверніть увагу, що друге призведе до показників продуктивності копії масиву. Якщо підпис (тип повернення) Get не є ICollection, то перший не буде працювати, якщо він не IEnumerable, то другий не буде працювати.


Після вашого роз’яснення до запитання та коментарів, я особисто заявляю про повернення типу _item.Get ("001") до ICollection. Це означає, що вам не доведеться робити будь-який кастинг або перетворення (за допомогою ToList / ToArray), що передбачає непотрібну операцію створення / копіювання.

// Leave this the same
public ICollection<Item> Items { get; set; }

// Change function signature here:
// As you mention Item uses the same underlying type, just return an ICollection<T>
public ICollection<Item> Get(string value); 

// Ideally here you want to call .Count on the collectoin, not .Count() on 
// IEnumerable, as this will result in a new Enumerator being created 
// per loop iteration
for (var index = 0; index < Items.Count(); index++) 

З найкращими побажаннями,


1
Підпис: IEnumerable <T> Get (рядок pk); Елементи використовуються для зберігання записів, які повертаються. Пізніше я перебираю їх, щоб створити звіт. Я б добре використовував усе, що працює. Яким, на вашу думку, буде найкращий тип типу даних?
Samantha JT Star

1
Я б запропонував змінити тип даних елементів на IEnumerable <T>, щоб він відповідав Get, або змінити тип повернення Get to ICollection <T>, щоб він відповідав пунктам. Я припускаю, що ці два є одним і тим же базовим типом, що просто оголошено по-різному? ЯКЩО вони одного типу, яких ви хочете уникати, використовуючи ToList () або ToArray (), оскільки вони виконують непотрібне виділення пам'яті та копіювання масиву. Якщо вони не одного типу, вам доведеться здійснити певне перетворення
доктор Ендрю Бернетт-Томпсон,

Я додав до запитання, щоб показати, де я пізніше використовую елементи. Ви маєте рацію, коли говорите про один і той же основний тип.
Samantha JT Star

Гаразд, тоді я б просто змінив тип повернення Get, оскільки тоді вам не потрібно виконувати будь-яке перетворення (через ToList / ToArray, що є повільним) або кастинг. Сподіваюся, це допомагає :)
Доктор Ендрю Бернетт-Томпсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.