IEnumerable vs List - จะใช้อะไร? พวกเขาทำงานอย่างไร


677

ฉันสงสัยว่า Enumerators ทำงานอย่างไรและ LINQ พิจารณาตัวเลือกสองอย่างง่าย ๆ เหล่านี้:

List<Animal> sel = (from animal in Animals 
                    join race in Species
                    on animal.SpeciesKey equals race.SpeciesKey
                    select animal).Distinct().ToList();

หรือ

IEnumerable<Animal> sel = (from animal in Animals 
                           join race in Species
                           on animal.SpeciesKey equals race.SpeciesKey
                           select animal).Distinct();

ฉันเปลี่ยนชื่อของวัตถุดั้งเดิมของฉันเพื่อให้ดูเหมือนเป็นตัวอย่างทั่วไปมากขึ้น แบบสอบถามเองไม่สำคัญ สิ่งที่ฉันต้องการถามคือ:

foreach (Animal animal in sel) { /*do stuff*/ }
  1. ฉันสังเกตเห็นว่าถ้าฉันใช้IEnumerableเมื่อฉันตรวจแก้จุดบกพร่องและตรวจสอบ "sel" ซึ่งในกรณีนี้คือ IEnumerable มันมีสมาชิกที่น่าสนใจ: "Inner", "outer", "outerKeySelector" และ "outerKeySelector" 2 ตัวสุดท้ายนี้ปรากฏ ที่จะได้รับมอบหมาย สมาชิก "ภายใน" ไม่มีอินสแตนซ์ "สัตว์" ในนั้น แต่เป็นอินสแตนซ์ "สปีชีส์" ซึ่งแปลกสำหรับฉันมาก สมาชิก "outer" ประกอบด้วยอินสแตนซ์ "Animal" ฉันคิดว่าผู้ได้รับมอบหมายทั้งสองเป็นผู้กำหนดว่าจะเข้าไปทางไหนและเกิดอะไรขึ้นบ้าง

  2. ฉันสังเกตเห็นว่าถ้าฉันใช้ "Distinct" "inner" มี 6 รายการ (ไม่ถูกต้องเนื่องจากมี 2 Distinct เท่านั้น) แต่ "outer" มีค่าที่ถูกต้อง อีกครั้งอาจเป็นวิธีการมอบหมายกำหนดนี้ แต่นี่เป็นบิตมากกว่าที่ฉันรู้เกี่ยวกับ IEnumerable

  3. สำคัญที่สุดข้อใดของสองตัวเลือกคือประสิทธิภาพที่ดีที่สุด?

รายการแปลงความชั่วร้ายผ่านทาง.ToList()?

หรืออาจจะใช้ตัวแจงนับโดยตรง

หากทำได้โปรดอธิบายหรืออธิบายลิงก์บางอันที่อธิบายการใช้ IEnumerable นี้

คำตอบ:


739

IEnumerableอธิบายพฤติกรรมในขณะที่รายการเป็นการใช้งานของพฤติกรรมนั้น เมื่อคุณใช้IEnumerableคุณเปิดโอกาสให้คอมไพเลอร์มีโอกาสเลื่อนงานจนกว่าจะถึงเวลาต่อมา ถ้าคุณใช้ ToList () คุณบังคับให้คอมไพเลอร์ตรวจสอบผลลัพธ์อีกครั้งทันที

เมื่อใดก็ตามที่ฉัน "แสดงออก" LINQ นิพจน์ฉันใช้IEnumerableเพราะโดยเฉพาะการระบุพฤติกรรมที่ฉันให้โอกาส LINQ เพื่อเลื่อนการประเมินผลและอาจเพิ่มประสิทธิภาพของโปรแกรม จำไว้ว่า LINQ ไม่สร้าง SQL เพื่อสืบค้นฐานข้อมูลจนกว่าคุณจะระบุหรือไม่ พิจารณาสิ่งนี้:

public IEnumerable<Animals> AllSpotted()
{
    return from a in Zoo.Animals
           where a.coat.HasSpots == true
           select a;
}

public IEnumerable<Animals> Feline(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Felidae"
           select a;
}

public IEnumerable<Animals> Canine(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Canidae"
           select a;
}

ตอนนี้คุณมีวิธีที่เลือกตัวอย่างเริ่มต้น ("AllSpotted") รวมทั้งตัวกรองบางตัวแล้ว ดังนั้นตอนนี้คุณสามารถทำสิ่งนี้:

var Leopards = Feline(AllSpotted());
var Hyenas = Canine(AllSpotted());

ดังนั้นเร็วกว่าการใช้ List over IEnumerable? เฉพาะในกรณีที่คุณต้องการป้องกันไม่ให้แบบสอบถามดำเนินการมากกว่าหนึ่งครั้ง แต่โดยรวมแล้วดีขึ้นหรือไม่ ในด้านบน Leopards และ Hyenas จะถูกแปลงเป็นคิวรี่ SQL เดี่ยวๆ และฐานข้อมูลจะคืนค่าแถวที่เกี่ยวข้องเท่านั้น แต่ถ้าเราได้ส่งคืนรายการจากAllSpotted()แล้วมันอาจทำงานช้าลงเนื่องจากฐานข้อมูลสามารถส่งคืนข้อมูลได้มากกว่าที่จำเป็นจริงๆและเราเสียวงจรในการทำการกรองในไคลเอ็นต์

ในโปรแกรมมันอาจจะเป็นการดีกว่าถ้าคุณเลื่อนการแปลงคิวรี่ของคุณไปเป็นลิสต์จนกว่าจะถึงตอนท้ายดังนั้นถ้าฉันจะแจกแจงผ่าน Leopards และ Hyenas มากกว่าหนึ่งครั้งฉันจะทำสิ่งนี้:

List<Animals> Leopards = Feline(AllSpotted()).ToList();
List<Animals> Hyenas = Canine(AllSpotted()).ToList();

11
ฉันคิดว่าพวกเขาอ้างถึงทั้งสองด้านของการเข้าร่วม ถ้าคุณทำ "เลือก * จากสัตว์เข้าร่วมสายพันธุ์ ... " ส่วนด้านในของการเข้าร่วมคือสัตว์และส่วนนอกคือพันธุ์
Chris Wenham

10
เมื่อฉันอ่านคำตอบเกี่ยวกับ: IEnumerable <T> vs IQueryable <T>ฉันเห็นคำอธิบายแบบอะนาล็อกดังนั้น IEnumerable บังคับให้รันไทม์ใช้ LINQ กับวัตถุเพื่อสอบถามคอลเลกชันโดยอัตโนมัติ ดังนั้นฉันจึงสับสนระหว่าง 3 ประเภทนี้ stackoverflow.com/questions/2876616//
Bronek

4
@Bonek คำตอบที่คุณเชื่อมโยงนั้นเป็นจริง IEnumerable<T>จะเป็น LINQ-To-Objects หลังจากส่วนแรกหมายถึงการพบทั้งหมดจะต้องถูกส่งกลับเพื่อเรียกใช้แมว ในทางกลับกันIQuertable<T>จะช่วยให้แบบสอบถามได้รับการปรับปรุงดึงลง Felines ด่างเท่านั้น
เนท

21
คำตอบนี้ทำให้เข้าใจผิดมาก! ความคิดเห็นของ @ Nate อธิบายว่าทำไม หากคุณใช้ IEnumerable <T> ตัวกรองจะเกิดขึ้นในฝั่งไคลเอ็นต์ไม่ว่าจะเกิดอะไรขึ้น
ฮันส์

5
ใช่ AllSpotted () จะทำงานสองครั้ง ปัญหาที่ใหญ่กว่ากับคำตอบนี้คือคำสั่งต่อไปนี้: "ในข้างต้น Leopards และ Hyenas ได้รับการแปลงเป็นแบบสอบถาม SQL เดียวแต่ละครั้งและฐานข้อมูลจะส่งกลับแถวที่เกี่ยวข้องเท่านั้น" สิ่งนี้เป็นเท็จเนื่องจากคำสั่ง where ถูกเรียกบน IEnumerable <> และรู้เพียงวิธีวนลูปผ่านวัตถุที่มาจากฐานข้อมูลแล้ว หากคุณทำการคืนค่า AllSpotted () และพารามิเตอร์ของ Feline () และ Canine () ไปเป็น IQueryable ตัวกรองจะเกิดขึ้นใน SQL และคำตอบนี้จะสมเหตุสมผล
ฮันส์

178

มีบทความที่ดีมากเขียนโดย: Claudio Bernasconi ของ TechBlog ที่นี่: เมื่อใดควรใช้ IEnumerable, ICollection, IList และ List

ที่นี่มีข้อมูลพื้นฐานเกี่ยวกับสถานการณ์และฟังก์ชั่น:

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่


25
มันควรจะชี้ให้เห็นว่าบทความนี้มีไว้สำหรับส่วนสาธารณะหันรหัสของคุณไม่ใช่งานภายใน ListคือการดำเนินการIListและเป็นเช่นนี้มีฟังก์ชันการทำงานพิเศษที่ด้านบนของผู้ที่อยู่ในIList(เช่นSort, Find, InsertRange) หากคุณบังคับให้คุณใช้IListเกินListคุณจะสูญเสียวิธีการเหล่านี้ที่คุณอาจต้องการ
Jonathan Twite

4
อย่าลืมIReadOnlyCollection<T>
Dandré

2
มันอาจจะมีประโยชน์หากคุณรวมอาร์เรย์ธรรมดาไว้[]ที่นี่เช่นกัน
jbyrd

ในขณะที่อาจขมวดคิ้วได้ขอขอบคุณที่แบ่งปันกราฟิกและบทความนี้
Daniel

134

คลาสที่ใช้IEnumerableช่วยให้คุณใช้foreachไวยากรณ์

โดยทั่วไปมีวิธีการรับรายการถัดไปในคอลเลกชัน ไม่จำเป็นต้องมีทั้งคอลเลกชันที่จะอยู่ในหน่วยความจำและไม่รู้ว่ามีกี่ไอเท็มอยู่ในนั้นforeachเพียงแค่เก็บไอเท็มถัดไปจนกว่ามันจะหมด

สิ่งนี้มีประโยชน์มากในบางสถานการณ์เช่นในตารางฐานข้อมูลขนาดใหญ่ที่คุณไม่ต้องการคัดลอกข้อมูลทั้งหมดลงในหน่วยความจำก่อนที่คุณจะเริ่มประมวลผลแถว

ตอนนี้Listใช้IEnumerableแต่เป็นตัวแทนของคอลเลกชันทั้งหมดในหน่วยความจำ หากคุณมีIEnumerableและคุณโทรหา.ToList()คุณสร้างรายการใหม่ที่มีเนื้อหาของการแจงนับในหน่วยความจำ

การแสดงออกของคุณ LINQ foreachผลตอบแทนนับและโดยค่าเริ่มต้นรันแสดงออกเมื่อคุณย้ำผ่านการใช้ IEnumerableLINQ รันคำสั่งเมื่อคุณย้ำแต่คุณสามารถบังคับให้มันย้ำเร็วโดยใช้foreach.ToList()

นี่คือสิ่งที่ฉันหมายถึง:

var things = 
    from item in BigDatabaseCall()
    where ....
    select item;

// this will iterate through the entire linq statement:
int count = things.Count();

// this will stop after iterating the first one, but will execute the linq again
bool hasAnyRecs = things.Any();

// this will execute the linq statement *again*
foreach( var thing in things ) ...

// this will copy the results to a list in memory
var list = things.ToList()

// this won't iterate through again, the list knows how many items are in it
int count2 = list.Count();

// this won't execute the linq statement - we have it copied to the list
foreach( var thing in list ) ...

2
แต่จะเกิดอะไรขึ้นถ้าคุณรัน foreach บน IEnumerable โดยไม่ต้องแปลงเป็นรายการแรก ? มันนำมารวมกันในหน่วยความจำหรือไม่? หรือว่ามันยกตัวอย่างองค์ประกอบทีละคนในขณะที่มันวนซ้ำรอบวง foreach? ขอบคุณ
Pap

@Pap หลัง: มันรันอีกครั้งไม่มีอะไรถูกแคชในหน่วยความจำโดยอัตโนมัติ
Keith

ดูเหมือนกุญแจสำคัญคือ 1) สิ่งทั้งหมดในความทรงจำหรือไม่ 2) IEnumerable ให้ฉันใช้foreachในขณะที่รายการจะไปโดยพูดดัชนี ตอนนี้ถ้าผมอยากจะรู้ว่านับ / ความยาวของthingก่อน IEnumerable จะไม่ช่วยใช่มั้ย?
Jeb50

@ Jeb50 ไม่ว่า - ทั้งListและการดำเนินการArray IEnumerableคุณสามารถคิดว่าIEnumerableเป็นตัวหารร่วมที่ต่ำที่สุดที่ใช้ได้กับทั้งในคอลเลกชันหน่วยความจำและของใหญ่ที่ได้หนึ่งรายการต่อครั้ง เมื่อคุณโทรหาIEnumerable.Count()คุณอาจกำลังโทรหา.Lengthอสังหาริมทรัพย์ที่รวดเร็วหรือผ่านคอลเล็กชั่นทั้งหมดประเด็นก็คือเมื่อIEnumerableคุณไม่รู้ นั่นอาจเป็นปัญหา แต่ถ้าคุณเพียงแค่ไปforeachคุณก็ไม่สนใจรหัสของคุณจะทำงานร่วมกับArrayหรือDataReaderเหมือนกัน
Keith

1
@MFouadKajj ฉันไม่ทราบว่าคุณกำลังใช้สแต็กอะไร แต่เกือบจะแน่นอนที่จะไม่ขอแต่ละแถว เซิร์ฟเวอร์จะเรียกใช้คิวรีและคำนวณจุดเริ่มต้นของชุดผลลัพธ์ แต่ไม่ได้ผลลัพธ์ทั้งหมด สำหรับชุดผลลัพธ์ขนาดเล็กน่าจะเป็นการเดินทางครั้งเดียวสำหรับรายการใหญ่คุณกำลังส่งคำขอแถวเพิ่มเติมจากผลลัพธ์ แต่จะไม่เรียกใช้แบบสอบถามทั้งหมดอีกครั้ง
Keith

97

ไม่มีใครพูดถึงความแตกต่างที่สำคัญอย่างหนึ่งโดยเฉพาะอย่างยิ่งแดกดันตอบคำถามที่ปิดเป็นซ้ำนี้

IEnumerable เป็นแบบอ่านอย่างเดียวและ List ไม่

ดูความแตกต่างระหว่างรายการจริงและ IEnumerable


จากการติดตามนั้นเป็นเพราะส่วนต่อประสานอินเตอร์เฟสหรือเนื่องจากส่วนขยายรายการ? คือ IList ก็อ่านอย่างเดียวเช่นกัน?
Jason Masters

IList ไม่ได้เป็นแบบอ่านอย่างเดียว - docs.microsoft.com/en-us/dotnet/api/ … IEnumerable นั้นเป็นแบบอ่านอย่างเดียวเนื่องจากไม่มีวิธีการใด ๆ ในการเพิ่มหรือลบสิ่งใด ๆ เมื่อมันถูกสร้างขึ้นมันเป็นหนึ่งในอินเตอร์เฟสพื้นฐานซึ่ง IList ขยาย (ดูลิงค์)
CAD bloke

67

สิ่งสำคัญที่สุดที่ต้องตระหนักคือการใช้ Linq แบบสอบถามจะไม่ได้รับการประเมินในทันที มันจะทำงานเฉพาะในส่วนของการวนซ้ำผ่านผลลัพธ์IEnumerable<T>ในforeach - นั่นคือสิ่งที่ตัวแทนประหลาดทั้งหมดกำลังทำอยู่

ดังนั้นตัวอย่างแรกประเมินแบบสอบถามทันทีโดยการโทรToListและวางผลลัพธ์แบบสอบถามในรายการ
ตัวอย่างที่สองส่งกลับค่าIEnumerable<T>ที่มีข้อมูลทั้งหมดที่จำเป็นในการเรียกใช้แบบสอบถามในภายหลัง

ในแง่ของประสิทธิภาพคำตอบคือมันขึ้นอยู่กับ หากคุณต้องการประเมินผลลัพธ์ในครั้งเดียว (พูดว่าคุณกำลังกลายพันธุ์โครงสร้างที่คุณทำการสืบค้นในภายหลังหรือถ้าคุณไม่ต้องการให้การวนซ้ำซ้ำอีกเป็นIEnumerable<T>เวลานาน) ให้ใช้รายการ อื่นใช้ IEnumerable<T>ค่าเริ่มต้นควรใช้การประเมินตามความต้องการในตัวอย่างที่สองเนื่องจากโดยทั่วไปจะใช้หน่วยความจำน้อยกว่าเว้นแต่จะมีเหตุผลเฉพาะในการจัดเก็บผลลัพธ์ในรายการ


สวัสดีและขอบคุณสำหรับการตอบกลับ :: -) เรื่องนี้ทำให้ฉันสงสัยเกือบทั้งหมด ความคิดใดที่ว่าเหตุใดจึงนับเป็น "แยก" เป็น "ภายใน" และ "นอก"? สิ่งนี้เกิดขึ้นเมื่อฉันตรวจสอบองค์ประกอบในโหมดดีบั๊ก / เบรคด้วยเมาส์ นี่อาจจะเป็นผลงานของ Visual Studio หรือไม่? ระบุในจุดและระบุอินพุตและเอาต์พุตของ Enum?
Axonn

5
นั่นคือการJoinทำงานของมัน - ด้านในและด้านนอกเป็นสองด้านของการเข้าร่วม โดยทั่วไปไม่ต้องกังวลกับสิ่งที่เกิดขึ้นจริงIEnumerablesเนื่องจากจะแตกต่างจากรหัสจริงของคุณอย่างสิ้นเชิง เพียงกังวลเกี่ยวกับผลลัพธ์ที่แท้จริงเมื่อคุณวนซ้ำมัน :)
thecoop

40

ข้อได้เปรียบของ IEnumerable คือการประมวลผลที่ถูกระงับ (โดยปกติจะมีฐานข้อมูล) แบบสอบถามจะไม่ถูกดำเนินการจนกว่าคุณจะวนซ้ำข้อมูล มันเป็นคิวรีที่รอจนกระทั่งมันจำเป็น

หากคุณเรียก ToList การสืบค้นจะถูกดำเนินการหรือ "materialized" ตามที่ฉันต้องการจะพูด

มีทั้งข้อดีและข้อเสีย ถ้าคุณเรียก ToList คุณอาจลบความลึกลับบางอย่างเมื่อถึงคิวรีที่ถูกเรียกใช้งาน หากคุณยึดติดกับ IEnumerable คุณจะได้รับประโยชน์จากโปรแกรมที่ไม่ทำงานจนกว่าจะจำเป็นจริงๆ


25

ฉันจะแบ่งปันแนวคิดที่ใช้ในทางที่ผิดที่ฉันตกลงไปในหนึ่งวัน:

var names = new List<string> {"mercedes", "mazda", "bmw", "fiat", "ferrari"};

var startingWith_M = names.Where(x => x.StartsWith("m"));

var startingWith_F = names.Where(x => x.StartsWith("f"));


// updating existing list
names[0] = "ford";

// Guess what should be printed before continuing
print( startingWith_M.ToList() );
print( startingWith_F.ToList() );

ผลลัพธ์ที่คาดหวัง

// I was expecting    
print( startingWith_M.ToList() ); // mercedes, mazda
print( startingWith_F.ToList() ); // fiat, ferrari

ผลลัพธ์ที่แท้จริง

// what printed actualy   
print( startingWith_M.ToList() ); // mazda
print( startingWith_F.ToList() ); // ford, fiat, ferrari

คำอธิบาย

ตามคำตอบอื่น ๆ การประเมินผลจะถูกเลื่อนออกไปจนกระทั่งการโทรToListหรือวิธีการอุทธรณ์ที่คล้ายกันเช่นToArrayหรือวิธีการภาวนาที่คล้ายกันเช่น

ดังนั้นฉันสามารถเขียนรหัสในกรณีนี้อีกครั้งเป็น:

var names = new List<string> {"mercedes", "mazda", "bmw", "fiat", "ferrari"};

// updating existing list
names[0] = "ford";

// before calling ToList directly
var startingWith_M = names.Where(x => x.StartsWith("m"));

var startingWith_F = names.Where(x => x.StartsWith("f"));

print( startingWith_M.ToList() );
print( startingWith_F.ToList() );

เล่น arround

https://repl.it/E8Ki/0


1
นั่นเป็นเพราะวิธีการของ linq (ส่วนขยาย) ซึ่งในกรณีนี้มาจาก IEnumerable ที่สร้างเฉพาะคิวรี่ แต่ไม่เรียกใช้งาน (หลังฉากใช้ต้นไม้นิพจน์) วิธีนี้คุณมีความเป็นไปได้ที่จะทำหลายสิ่งด้วยแบบสอบถามนั้นโดยไม่ต้องแตะข้อมูล (ในกรณีนี้คือข้อมูลในรายการ) รายการวิธีใช้แบบสอบถามที่เตรียมไว้และดำเนินการกับแหล่งข้อมูล
Bronek

2
ที่จริงแล้วฉันอ่านคำตอบทั้งหมดและคุณเป็นคนที่ฉันโหวตเพราะเห็นได้ชัดว่ามันแตกต่างระหว่างทั้งสองโดยไม่พูดถึง LINQ / SQL โดยเฉพาะ จำเป็นอย่างยิ่งที่จะต้องรู้ทั้งหมดนี้ก่อนที่คุณจะได้รับ LINQ / SQL ชื่นชม
BeemerGuy

นั่นคือความแตกต่างที่สำคัญในการอธิบาย แต่ "ผลลัพธ์ที่คาดหวัง" ของคุณไม่ได้คาดหวังจริงๆ คุณกำลังบอกว่ามันเป็น gotcha แบบแทนที่จะออกแบบ
Neme

@Neme ใช่มันเป็นความคาดหวังของฉันก่อนที่ฉันจะเข้าใจวิธีIEnumerableการทำงาน แต่ตอนนี้ไม่ได้มากขึ้นเนื่องจากผมรู้ว่า;)
เอเอ็มดี

15

IEnumerableหากสิ่งที่คุณต้องการจะทำคือระบุพวกเขาใช้

อย่างไรก็ตามระวังว่าการเปลี่ยนคอลเล็กชั่นดั้งเดิมที่แจกแจงนั้นเป็นการดำเนินการที่อันตราย - ในกรณีนี้คุณจะต้องToListก่อน สิ่งนี้จะสร้างองค์ประกอบลิสต์ใหม่สำหรับแต่ละองค์ประกอบในหน่วยความจำการแจงนับIEnumerableและมีประสิทธิภาพน้อยกว่าหากคุณระบุเพียงครั้งเดียว - แต่ปลอดภัยกว่าและบางครั้งListวิธีมีประโยชน์ (เช่นในการเข้าถึงแบบสุ่ม)


1
ฉันไม่แน่ใจว่าปลอดภัยที่จะบอกว่าการสร้างรายการหมายถึงประสิทธิภาพที่ลดลง
Steven Sudit

@ Steven: แน่นอนตามที่ thecoop และ Chris พูดบางครั้งอาจจำเป็นต้องใช้ List ในกรณีของฉันฉันได้ข้อสรุปว่าไม่ใช่ @ Daren: คุณหมายความว่าอย่างไร "จะสร้างรายการใหม่สำหรับแต่ละองค์ประกอบในหน่วยความจำ" บางทีคุณอาจหมายถึง "รายการรายการ"? :: -)
Axonn

@ แอกซอนใช่ฉันพูดถึงรายการ แก้ไขแล้ว.
Daren Thomas

@Steven หากคุณวางแผนที่จะย้ำกว่าองค์ประกอบในที่IEnumerableแล้วสร้างรายการเป็นครั้งแรก (และทำซ้ำมากกว่านั้น) หมายความว่าคุณย้ำกว่าองค์ประกอบสองครั้ง ดังนั้นหากคุณไม่ต้องการดำเนินการที่มีประสิทธิภาพมากขึ้นในรายการสิ่งนี้จะหมายถึงประสิทธิภาพที่ต่ำลง
Daren Thomas

3
@ jerhewet: มันเป็นความคิดที่ดีที่จะปรับเปลี่ยนลำดับการทำซ้ำ สิ่งเลวร้ายจะเกิดขึ้น บทคัดย่อจะรั่วไหล ปีศาจจะบุกเข้าไปในมิติของเราและสร้างความหายนะ ดังนั้นใช่.ToList()ช่วยที่นี่;)
Daren Thomas

5

นอกจากคำตอบทั้งหมดที่โพสต์ข้างต้นนี่คือสองเซ็นต์ของฉัน มีประเภทอื่น ๆ อีกมากมายนอกเหนือจากรายการที่ใช้ IEnumerable เช่น ICollection, ArrayList เป็นต้นดังนั้นหากเรามี IEnumerable เป็นพารามิเตอร์ของวิธีการใด ๆ เราสามารถส่งประเภทการรวบรวมใด ๆ ไปยังฟังก์ชัน นั่นคือเราสามารถมีวิธีการในการดำเนินการในสิ่งที่ไม่เป็นนามธรรมโดยเฉพาะ


1

มีหลายกรณี (เช่นรายการไม่สิ้นสุดหรือรายการใหญ่มาก) ซึ่ง IEnumerable ไม่สามารถแปลงเป็นรายการได้ ตัวอย่างที่ชัดเจนที่สุดคือตัวเลขสำคัญทั้งหมดผู้ใช้ facebook ที่มีรายละเอียดทั้งหมดหรือรายการทั้งหมดบนอีเบย์

ความแตกต่างก็คือวัตถุ "รายการ" จะถูกเก็บไว้ "ที่นี่และตอนนี้" ในขณะที่วัตถุ "IEnumerable" ทำงาน "ครั้งละหนึ่ง" ดังนั้นถ้าฉันจะผ่านรายการทั้งหมดใน eBay หนึ่งครั้งจะเป็นสิ่งที่แม้แต่คอมพิวเตอร์ขนาดเล็กสามารถจัดการได้ แต่ ". ToList ()" จะทำให้ฉันหมดความจำแน่นอนไม่ว่าคอมพิวเตอร์ของฉันจะใหญ่ขนาดไหน คอมพิวเตอร์ไม่สามารถมีและจัดการกับข้อมูลจำนวนมหาศาลได้

[แก้ไข] - ไม่จำเป็นต้องพูด - ไม่ใช่ "อย่างนี้หรืออย่างนั้น" บ่อยครั้งที่ควรใช้ทั้งรายการและ IEnumerable ในคลาสเดียวกัน ไม่มีคอมพิวเตอร์ในโลกที่สามารถแสดงรายการหมายเลขเฉพาะทั้งหมดได้เนื่องจากตามคำจำกัดความนี้จะต้องใช้หน่วยความจำจำนวนนับไม่ถ้วน แต่คุณสามารถคิดถึงอันclass PrimeContainerที่ประกอบด้วยอัน IEnumerable<long> primesซึ่งด้วยเหตุผลที่ชัดเจนก็ประกอบSortedList<long> _primesไปด้วย จำนวนเฉพาะทั้งหมดที่คำนวณไปแล้ว นายกถัดไปที่จะตรวจสอบจะถูกเรียกใช้เฉพาะช่วงเวลาที่มีอยู่เท่านั้น (จนถึงรากที่สอง) ด้วยวิธีนี้คุณจะได้รับทั้งสองครั้งครั้งเดียว (IEnumerable) และรายการที่ดีของ "จำนวนเฉพาะ" ซึ่งเป็นการประมาณที่ดีของรายการทั้งหมด (ไม่มีที่สิ้นสุด)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.