เหตุใดฉันจึงควรใช้รายการ <T> บน IEnumerable <T>


24

ในแอปพลิเคชันเว็บ ASP.net MVC4 ของฉันฉันใช้ IEnumerables พยายามติดตามมนต์เพื่อเขียนโปรแกรมไปยังส่วนต่อประสานไม่ใช่เพื่อการนำไปใช้

Return IEnumerable(Of Student)

VS

Return New List(Of Student)

มีคนบอกให้ฉันใช้ List และไม่ใช่ IEnumerable เพราะรายการบังคับให้แบบสอบถามดำเนินการและ IEumerable ไม่

นี่เป็นวิธีปฏิบัติที่ดีที่สุดจริง ๆ หรือ มีทางเลือกอื่นอีกไหม? ฉันรู้สึกแปลก ๆ ที่ใช้วัตถุที่เป็นรูปธรรมซึ่งสามารถใช้ส่วนต่อประสาน ความรู้สึกแปลก ๆ ของฉันเป็นธรรมหรือไม่?


2
เอ่อก่อนทำไมมันเป็นสิ่งที่ดีที่จะบังคับให้แบบสอบถามดำเนินการ? ประการที่สองคุณควรตรวจสอบและรวบรวมการเรียกใช้ฐานข้อมูลเพื่อประเมินว่าการพิจารณาด้านเทคนิคนี้มีข้อดีหรือไม่
user16764

2
มีคำกล่าวว่าควรดำเนินการค้นหาทั้งหมดเพื่อให้โมเดลเสร็จสมบูรณ์และพร้อมสำหรับการดู คือมุมมองที่ควรได้รับทุกอย่างและไม่ต้องสืบค้นฐานข้อมูล
Rowan Freeman

3
คำถาม StackOverflowนี้ครอบคลุมค่อนข้างดี
Karl Bielefeldt

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

2
"มีการกล่าวว่าแบบสอบถามทั้งหมดควรถูกดำเนินการเพื่อให้โมเดลเสร็จสิ้นและโหลดพร้อมสำหรับมุมมองนั่นคือมุมมองควรได้รับทุกอย่างและไม่ต้องสืบค้นฐานข้อมูล" นั่นเป็นเรื่องไร้สาระ หากคุณผ่าน IEnumerable มุมมองของคุณจะไม่ทราบหรือไม่สนใจว่าเป็นการสอบถามฐานข้อมูลหรือไม่ และนั่นคือวิธีที่ควรจะเป็น
user16764

คำตอบ:


21

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

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

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

เกี่ยวกับ MVC ไม่มีอะไรพิเศษที่จะต้องทราบที่นี่ มันจะเป็นไปตามกฎเวลาการดำเนินการเช่นเดียวกับส่วนที่เหลือของ. NET ฉันคิดว่าคุณอาจมีใครสักคนที่สับสนเพราะความหมายในการดำเนินการล่าช้าในอดีตและตำหนิมันใน MVC บอกคุณว่ามันเกี่ยวข้องกัน แต่อย่างใด ไม่. ความหมายของการดำเนินการล่าช้าทำให้ทุกคนสับสนในตอนแรก อีกครั้งแม้ว่าคุณจะไม่ต้องกังวลจนกว่าคุณจะมั่นใจได้ว่าการสืบค้น LINQ จะไม่ถูกดำเนินการสองครั้งหรือต้องการให้มีการดำเนินการตามลำดับที่สัมพันธ์กับรหัสอื่น ๆ ณ จุดนี้กำหนดตัวแปรของคุณให้กับตัวเอง ToList () เพื่อบังคับให้ดำเนินการและคุณจะไม่เป็นไร


การให้ IEnumerables ดูเป็นสิ่งที่ไม่ดีหรือไม่? คุณควรให้รายการเพื่อให้แบบสอบถามได้รับการดำเนินการตามเวลาที่ได้รับมุมมอง
Rowan Freeman

@RowanFreeman ฉันเพิ่งเพิ่มการแก้ไขเพื่อตอบคำถามนี้ ฉันคิดว่าคุณมีใครบางคนที่พบเจอสิ่งที่พวกเขาไม่เข้าใจทั้งหมด (ไม่สามารถตำหนิพวกเขาได้การประวิงเวลาล่าช้านั้นซับซ้อนและสับสนอย่างมาก) และชอล์กจนถึง joojoo ที่ไม่ดีแทนที่จะทำงานเพื่อทำความเข้าใจพฤติกรรมทั้งหมดของการประหารชีวิตล่าช้า อรรถศาสตร์
จิมมี่ฮอฟฟา

คำตอบที่ดี ดังนั้นฉันจะต้องใช้. ToList () จริงหรือไม่ จนถึงตอนนี้แอปพลิเคชันของฉันทำงานได้ดีโดยใช้เพียง IEnumerables และส่งผ่านจากแบบจำลองไปยังมุมมอง ไม่มีรายการหรือ. ToList () คำถามของฉันไม่ใช่หนึ่งในการทำงาน - ฉันรู้ว่าแอปพลิเคชันของฉันทำงาน คำถามของฉันเป็นหนึ่งในแนวปฏิบัติที่ดีที่สุด
Rowan Freeman

4
@RowanFreeman แนวปฏิบัติที่เหมาะสมที่สุดคือการใช้ส่วนต่อประสานที่น้อยที่สุดที่ยังคงตรงตามความต้องการของคุณ IEnumerable กำลังทำสิ่งนี้อยู่ในขณะนี้สำหรับคุณดังนั้นอย่ากังวลกับการเปลี่ยนแปลง ดังที่กล่าวว่าวันหนึ่งจะมาถึงเมื่อคุณมีคิวรีที่เรียกใช้งาน 3 หรือ 10 ครั้งและไม่เข้าใจว่าทำไมหรือคาดว่าคิวรีจะทำงานก่อนที่จะแทรกเฉพาะเพื่อค้นหามันจะทำงานหลังจากนั้นนี่คือเวลาที่คุณต้องจำ () จะบังคับให้ดำเนินการเมื่อคุณต้องการและการทำซ้ำจำนวน IEnumerable จากแบบสอบถาม LINQ หลายครั้งจะดำเนินการแบบสอบถามทั้งหมดหลายครั้ง; แก้ไขการกระทำของคุณเมื่อมีเหตุการณ์เหล่านั้นเกิดขึ้น
Jimmy Hoffa

1
คุณไม่ควรใช้ - Listผ่านการListบอกเป็นนัยว่าเนื้อหาของรายการกำลังจะถูกแก้ไข หากคุณต้องการที่จะกลับไปคอลเลกชัน, IReadOnlyCollectionการใช้งาน Listมีไว้สำหรับใช้ภายในเมธอดและสำหรับการแลกเปลี่ยนระหว่างเมธอดที่แก้ไขรายการ แค่นั้นแหละ!
ErikE

7

มีสองประเด็น

IENumerable<Data> query = MyQuery();

//Later
foreach (Data item in query) {
  //Process data
}

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

ปัญหาที่สองคือการเชื่อมต่อของคุณจะไม่ถูกนำออกใช้จนกว่าการวนรอบ "ข้อมูลกระบวนการ" จะเสร็จสมบูรณ์ นี่เป็นปัญหาเฉพาะถ้า "ข้อมูลกระบวนการ" ซับซ้อน สิ่งนี้ถูกกล่าวถึงที่http://msdn.microsoft.com/en-us/library/bb386929.aspx :

ถามการเชื่อมต่อฐานข้อมูลของฉันยังคงเปิดนานเท่าไหร่

A. โดยปกติแล้วการเชื่อมต่อจะยังคงเปิดอยู่จนกว่าคุณจะใช้ผลลัพธ์แบบสอบถาม หากคุณคาดว่าจะใช้เวลาในการประมวลผลผลลัพธ์ทั้งหมดและไม่คัดค้านการแคชผลลัพธ์ให้ใช้ ToList กับแบบสอบถาม ในสถานการณ์ทั่วไปที่แต่ละวัตถุถูกประมวลผลเพียงครั้งเดียวโมเดลการสตรีมจะดีกว่าทั้ง DataReader และ LINQ ไปยัง SQL

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

ตามกฎทั่วไปฉันแนะนำให้หลีกเลี่ยงการวนซ้ำ IEnumerable มากกว่าหนึ่งครั้ง สมมติว่าผู้บริโภครหัสของคุณปฏิบัติตามกฎนี้ฉันไม่คิดว่าจะกังวลว่ามีบางคนอาจเข้าสู่ฐานข้อมูลสองครั้งด้วยการดำเนินการค้นหาสองครั้ง


1

ประโยชน์ของการแจกแจงIEnumerableต้นอื่นก็คือข้อยกเว้นจะถูกโยนในสถานที่ที่เหมาะสม ช่วยในการดีบัก

ตัวอย่างเช่นหากคุณได้รับข้อยกเว้นการหยุดชะงักในมุมมองมีดโกนของคุณมุมมองมีดโกนจะไม่ชัดเจนเหมือนกับการยกเว้นที่เกิดขึ้นระหว่างหนึ่งในวิธีการเข้าถึงข้อมูลของคุณ


วิธีการใด ๆ ที่ส่งคืนสิ่งIEnumerableที่โยนได้อาจเป็นการทำผิดพลาด IEnumerableวิธีการรอการตัดบัญชีควรแบ่งออกเป็นสองวิธีการหนึ่งที่ไม่รอการตัดบัญชีตรวจสอบพารามิเตอร์และตั้งค่าการขว้างหากจำเป็น (พูดเนื่องจากอาร์กิวเมนต์ที่เป็นโมฆะ) จากนั้นจะส่งคืนการเรียกไปยังการใช้งานส่วนตัวซึ่งถูกเลื่อนออกไป ฉันไม่คิดว่าความคิดเห็นของฉันขัดแย้งกับคำตอบของคุณอย่างสมบูรณ์ แต่คิดว่าคุณได้ทิ้งประเด็นสำคัญไว้ในคำตอบของคุณซึ่งเป็นความหมายเชิงความหมายของการใช้IEnumerableกับการเปรียบเทียบกับList(การกลายพันธุ์) กับIReadOnlyCollection(ไม่เป็นประโยชน์ต่อ เลื่อน)
ErikE
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.