ไม่สามารถแปลงจาก IEnumerable <T> เป็น ICollection <T>


94

ฉันได้กำหนดสิ่งต่อไปนี้:

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 (string) (ประเภทการส่งคืนโดยเฉพาะ) ได้หรือไม่
Dr. Andrew Burnett-Thompson

ทำไมไม่เปลี่ยนประเภทแบบนี้ public IEnumerable<Item> Items { get; set; }คุณมีเหตุผลอะไรเป็นพิเศษICollectionหรือไม่?
Shadow Wizard กำลังฉีดวัคซีน

IEnumerable <T> รับ (สตริง pk);
Samantha JT Star

คำตอบ:


116

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 loop:

foreach(var item in Items)

1
ICollection เพิ่มฟังก์ชันการทำงานเพิ่มเติมอะไรบ้าง
Samantha JT Star

7
ICollection<T>สามารถจัดการได้ (ดูรายละเอียดในเอกสาร ) ในขณะที่IEnumerable<T>สามารถระบุได้เท่านั้น
Anders Abel

ฉันจำเป็นต้องมีบางอย่างที่สามารถเรียกใช้การสืบค้น LINQ ที่แตกต่าง ฉันไม่จำเป็นต้องเพิ่มหรือทำอะไรแบบนั้นในรายการ นั่นหมายความว่าฉันจะดีกว่ากับ ICollection
Samantha JT Star

LINQ ทำงานบนIEnumerable<T>จึงIEnumerable<T>จะเพียงพอในกรณีที่
Anders Abel

31

คุณไม่สามารถแปลงโดยตรงจากไปIEnumerable<T> ICollection<T>คุณสามารถใช้ToListวิธีIEnumerable<T>การแปลงเป็นไฟล์ICollection<T>

someICollection = SomeIEnumerable.ToList();


สิ่งนี้ใช้ได้กับฉัน แต่เป็นความคิดที่ดีสำหรับฉันที่จะแปลงหรือฉันจะดีกว่าถ้าใช้ IEnumerable เป็นประเภทสำหรับรายการ หากฉันใช้ IEnumerable ฉันจะทำให้มันสามารถดำเนินการกับรายการต่างๆได้มากขึ้นหากจำเป็นในโปรแกรมของฉันในภายหลัง
Samantha JT Star

ICollection แล้ว IEnumerable หากคุณกังวลเกี่ยวกับการดำเนินการที่มีอยู่ฉันคิดว่าคุณควรไป ICollection จะดีกว่าถ้าคุณสามารถอ่านความแตกต่างที่แท้จริงระหว่างทั้งสองแล้วตัดสินใจว่าคุณต้องการใช้อะไร
Haris Hasan

ฉันพยายามทำความเข้าใจว่าจะมีข้อดีอะไรบ้างหากใช้ ToList () เมื่อฉันมีข้อมูลแล้วฉันต้องการเรียกใช้การสืบค้น LINQ กับรายการ
Samantha JT Star

ToList () จะใช้งานได้ แต่ตามที่คุณได้ระบุไว้ในความคิดเห็นของคุณ Get () ส่งคืน ICollection ดังนั้นคุณเพียงแค่ทำการแคสต์ไปที่ ICollection <T> หรือดีกว่านั้นให้เปลี่ยนลายเซ็นส่งคืนของ Get to ICollection <T> . การใช้ ToList หรือ ToArray จะใช้งานได้ แต่จะต้องใช้การสร้างหน่วยความจำ / การคัดลอกโดยไม่จำเป็นด้วย
Dr. Andrew Burnett-Thompson

คุณสามารถเรียกใช้การสอบถาม LINQ กับทั้ง IEnumerable และ ICollection ข้อดี .. อย่างหนึ่งที่ฉันรู้ในตอนนี้คือ Count ICollection จะรักษาจำนวนและผลตอบแทนที่สามารถคำนวณได้ของ IE โดยการคำนวณจำนวนรายการที่มี ICollection มีวิธีการลบเพิ่มเติมซึ่ง Ienumerables ไม่มี
Haris Hasan

1

ข้อมูลเพิ่มเติมเกี่ยวกับคำถามที่รอดำเนินการ:

โปรดให้ข้อมูลเพิ่มเติมเกี่ยวกับประเภทของไอเทมและลายเซ็นของ Get

สองสิ่งที่คุณสามารถลองได้คือ:

  • การส่งคืนค่า _item ไปที่ (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 (string pk); รายการถูกใช้เพื่อเก็บบันทึกรายการที่ส่งคืน ต่อมาฉันจะทำซ้ำผ่านสิ่งเหล่านี้เพื่อสร้างรายงาน ฉันจะโอเคถ้าจะใช้อะไรก็ได้ที่ได้ผล คุณคิดว่าประเภทข้อมูลที่ดีที่สุดคืออะไร?
Samantha JT Star

1
ฉันขอแนะนำให้เปลี่ยนประเภทข้อมูลของรายการเป็น IEnumerable <T> เพื่อให้ตรงกับ Get หรือเปลี่ยนประเภทการส่งคืนของ Get to ICollection <T> เพื่อจับคู่รายการ ฉันถือว่าสองคนนี้เป็นประเภทพื้นฐานเดียวกันที่ประกาศแตกต่างกัน? หากเป็นประเภทเดียวกันคุณต้องการหลีกเลี่ยงการใช้ ToList () หรือ ToArray () เนื่องจากเป็นการจัดสรรหน่วยความจำที่ไม่จำเป็นและคัดลอกอาร์เรย์ หากไม่ใช่คนประเภทเดียวกันคุณต้องเปลี่ยนใจ
Dr. Andrew Burnett-Thompson

ฉันเพิ่มคำถามเพื่อแสดงว่าฉันอยู่ที่ไหนในภายหลังโดยใช้รายการ คุณพูดถูกต้องเมื่อพูดประเภทต้นแบบเดียวกัน
Samantha JT Star

ตกลงฉันจะเปลี่ยนประเภทการรับคืนเนื่องจากคุณไม่จำเป็นต้องทำการแปลงใด ๆ (ผ่าน ToList / ToArray ซึ่งช้า) หรือการแคสต์ หวังว่านี่จะช่วยได้ :)
Dr. Andrew Burnett-Thompson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.