Konvertieren von einer IEnumerable <T> in eine ICollection <T> nicht möglich

87

Ich habe folgendes definiert:

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

Wenn ich diesen Code ausführe:

Items = _item.Get("001");

Ich erhalte die folgende Nachricht:

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?)

Kann jemand erklären, was ich falsch mache. Ich bin sehr verwirrt über den Unterschied zwischen Enumerable, Collections und der Verwendung der ToList ()

Informationen hinzugefügt

Später in meinem Code habe ich Folgendes:

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

Wäre es in Ordnung, Elemente als IEnumerable zu definieren?

Samantha JT Star
quelle
3
Können Sie weitere Informationen zum Typ von _item und zur Signatur von Get (string) (insbesondere Rückgabetyp) bereitstellen?
Dr. Andrew Burnett-Thompson
Warum nicht den Typ so ändern? public IEnumerable<Item> Items { get; set; }Haben Sie einen besonderen Grund, es als zu haben ICollection?
Schatten-Assistent ist Ohr für Sie
IEnumerable <T> Get (string pk);
Samantha JT Star

Antworten:

109

ICollection<T>erbt von IEnumerable<T>so, um das Ergebnis von zuzuweisen

IEnumerable<T> Get(string pk)

Zu einem ICollection<T>gibt es zwei Möglichkeiten.

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

Die zweite Option ist flexibler, hat jedoch einen viel größeren Einfluss auf die Leistung. Eine andere Möglichkeit besteht darin, das Ergebnis als zu speichern, es IEnumerable<T>sei denn, Sie benötigen die zusätzliche Funktionalität, die von der ICollection<T>Schnittstelle hinzugefügt wird .

Zusätzlicher Leistungskommentar

Die Schleife, die Sie haben

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

arbeitet an einem, IEnumerable<T>aber es ist ineffizient; Jeder Aufruf von Count()erfordert eine vollständige Aufzählung aller Elemente. Verwenden Sie entweder eine Sammlung und die CountEigenschaft (ohne die Klammer) oder konvertieren Sie sie in eine foreach-Schleife:

foreach(var item in Items)
Anders Abel
quelle
1
Welche zusätzlichen Funktionen bietet ICollection?
Samantha JT Star
7
ICollection<T>kann manipuliert werden ( Details finden Sie im Dokument ), während ein IEnumerable<T>nur aufgezählt werden kann.
Anders Abel
Ich brauche etwas, wo ich verschiedene LINQ-Abfragen ausführen kann. Ich muss der Liste nichts dergleichen hinzufügen oder tun. Heißt das, ich wäre mit ICollection besser dran.
Samantha JT Star
LINQ funktioniert IEnumerable<T>so IEnumerable<T>, dass es in diesem Fall ausreicht.
Anders Abel
31

Sie können nicht direkt von IEnumerable<T>nach konvertieren ICollection<T>. Sie können die ToListMethode verwenden IEnumerable<T>, um es zu konvertierenICollection<T>

someICollection = SomeIEnumerable.ToList();

Haris Hasan
quelle
Das funktioniert bei mir. Aber ist es eine gute Idee für mich, zu konvertieren, oder wäre es besser, IEnumerable als Typ für Elemente zu verwenden. Wenn ich IEnumerable verwende, mache ich es dann, damit ich später in meinem Programm bei Bedarf weitere Aktionen für Elemente ausführen kann?
Samantha JT Star
ICollection implementiert bereits IEnumerable. Wenn Sie über die verfügbaren Aktionen besorgt sind, sollten Sie sich für ICollection entscheiden. Es ist besser, wenn Sie den tatsächlichen Unterschied zwischen den beiden lesen und dann entscheiden können, was Sie tatsächlich verwenden möchten
Haris Hasan
Ich versuche zu verstehen, welche Vorteile ich hätte, wenn ich ToList () verwenden würde. Sobald ich die Daten habe, möchte ich LINQ-Abfragen für Elemente ausführen.
Samantha JT Star
ToList () funktioniert, aber wie Sie in Ihren Kommentaren angegeben haben, gibt Get () eine ICollection zurück. Sie müssen also nur eine Umwandlung in ICollection <T> vornehmen oder noch besser die Rückgabesignatur von Get to ICollection <T> ändern . Die Verwendung von ToList oder ToArray funktioniert, es entsteht jedoch auch ein unnötiger Vorgang zum Erstellen von Speicher / Kopieren
Dr. Andrew Burnett-Thompson
Sie können LINQ-Abfragen sowohl für IEnumerable als auch für ICollection ausführen. Vorteile .. Eine, die ich derzeit kenne, ist, dass die Count ICollection die Anzahl und die Anzahl der IEnumerable-Rückgaben beibehält, indem berechnet wird, wie viele Elemente sie enthält. ICollection bietet eine zusätzliche Methode zum Entfernen, die Ienumerables nicht bietet
Haris Hasan
1

Bis weitere Informationen zu der Frage vorliegen:

Bitte geben Sie weitere Informationen zur Art des Artikels und zur Unterschrift von Get an

Zwei Dinge, die Sie ausprobieren können, sind:

  • Um den Rückgabewert von _item.Get to (ICollection) umzuwandeln
  • zweitens, um _item.Get ("001") zu verwenden. ToArray () oder _item.Get ("001"). ToList ()

Bitte beachten Sie, dass die zweite einen Leistungseinbruch für die Array-Kopie zur Folge hat. Wenn die Signatur (Rückgabetyp) von Get keine ICollection ist, funktioniert die erste nicht. Wenn sie nicht IEnumerable ist, funktioniert die zweite nicht.


Nach Ihrer Klarstellung zur Frage und in Kommentaren würde ich persönlich den Rückgabetyp von _item.Get ("001") an ICollection deklarieren. Dies bedeutet, dass Sie kein Casting oder keine Konvertierung (über ToList / ToArray) durchführen müssen, die einen unnötigen Erstellungs- / Kopiervorgang erfordern würde.

// 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++) 

Freundliche Grüße,

Dr. Andrew Burnett-Thompson
quelle
1
Die Signatur lautet: IEnumerable <T> Get (string pk); Items wird verwendet, um die zurückgegebenen Item-Datensätze zu speichern. Später durchlaufe ich diese, um einen Bericht zu erstellen. Ich wäre in Ordnung, alles zu verwenden, was funktioniert. Was ist Ihrer Meinung nach der beste Datentyp?
Samantha JT Star
1
Ich würde vorschlagen, den Datentyp von Items in IEnumerable <T> zu ändern, um mit Get übereinzustimmen, oder den Rückgabetyp von Get to ICollection <T> zu ändern, um mit Items übereinzustimmen. Ich nehme an, diese beiden sind der gleiche zugrunde liegende Typ, der gerade unterschiedlich deklariert wurde. WENN es sich um denselben Typ handelt, den Sie vermeiden möchten, verwenden Sie ToList () oder ToArray (), da dies eine unnötige Speicherzuweisung und Array-Kopie durchführt. Wenn sie nicht vom selben Typ sind, müssen Sie eine Konvertierung durchführen
Dr. Andrew Burnett-Thompson
Ich habe der Frage hinzugefügt, um zu zeigen, wo ich später Elemente verwende. Sie haben Recht, wenn Sie denselben zugrunde liegenden Typ sagen.
Samantha JT Star
Ok, dann würde ich einfach den Rückgabetyp von Get ändern, da Sie dann keine Konvertierung (über ToList / ToArray, was langsam ist) oder Casting durchführen müssen. Hoffe das hilft :)
Dr. Andrew Burnett-Thompson