เหตุใดจึงใช้ ICollection และไม่ใช่ IEnumerable หรือ List <T> ในหลาย ๆ ความสัมพันธ์ / หลายต่อหลายความสัมพันธ์


359

ICollection<T>ฉันเห็นมากในบทเรียนที่มีคุณสมบัติเป็นลูกศร

นี่เป็นข้อกำหนดที่จำเป็นสำหรับ Entity Framework หรือไม่ ฉันสามารถใช้IEnumerable?

อะไรคือวัตถุประสงค์หลักในการใช้งานICollectionแทนIEnumerableหรือแม้กระทั่งList<T>?

คำตอบ:


439

โดยปกติสิ่งที่คุณเลือกจะขึ้นอยู่กับวิธีการที่คุณต้องการเข้าถึง โดยทั่วไป - IEnumerable<>(MSDN: http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx ) สำหรับรายการของวัตถุที่ต้องทำซ้ำผ่านเท่านั้นICollection<>(MSDN: http: // msdn.microsoft.com/en-us/library/92t2ye13.aspx ) สำหรับรายการของวัตถุที่จำเป็นต้องทำซ้ำและแก้ไขList<>เพื่อดูรายการของวัตถุที่ต้องทำซ้ำผ่านแก้ไขจัดเรียง ฯลฯ (ดูที่นี่ สำหรับรายการทั้งหมด: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx )

จากมุมมองที่เฉพาะเจาะจงมากขึ้นการโหลดแบบขี้เกียจจะเข้ามาเล่นโดยเลือกประเภท ตามค่าเริ่มต้นคุณสมบัติการนำทางใน Entity Framework มาพร้อมกับการติดตามการเปลี่ยนแปลงและเป็นพร็อกซี เพื่อให้ผู้รับมอบฉันทะแบบไดนามิกเพื่อสร้างเป็นสถานที่ให้บริการนำทางชนิดเสมือนจริงจะต้องICollectionดำเนินการ

คุณสมบัติการนำทางที่แสดงถึงจุดสิ้นสุด "จำนวนมาก" ของความสัมพันธ์ต้องส่งคืนชนิดที่ใช้ ICollection โดยที่ T คือประเภทของวัตถุที่ปลายอีกด้านของความสัมพันธ์ - ข้อกำหนดสำหรับการสร้าง POCO Proxies MSDN

ข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดและการจัดการความสัมพันธ์MSDN


2
ถ้าอย่างนั้นListควรจะดีกว่านี้อีกใช่ไหม
Jan Carlo Viray

3
@JanCarloViray - ฉันมักจะใช้Listบ่อย แม้ว่าจะมีค่าใช้จ่ายมากที่สุด แต่ก็มีฟังก์ชั่นการใช้งานมากที่สุด
เทรวิส J

1
รายการถูกกำหนดเพิ่มเติมโดยตัวจัดทำดัชนีของพวกเขามากกว่าโดยความสามารถในการจัดเรียงพวกเขา (การมีตัวทำดัชนีจำนวนเต็มทำให้ง่ายต่อการเรียงลำดับบางสิ่ง แต่ไม่ใช่ข้อกำหนด)
phoog

2
สำหรับการแก้ไขของคุณการ จำกัด คุณสมบัติให้กับประเภทอินเตอร์เฟสนั้นไม่ได้เกี่ยวกับหน่วยความจำ แต่เกี่ยวกับการห่อหุ้ม ลองพิจารณา: private IEnumerable<int> _integers = new List<int> { 1, 2, 3 };ใช้หน่วยความจำเดียวกันกับprivate List<int> _integers = new List<int> { 1, 2, 3 };
phoog

13
@TravisJ: List<T>มีGetEnumerator()วิธีการแยกออกจากการดำเนินงานของซึ่งผลตอบแทนประเภทโครงสร้างที่ไม่แน่นอนIEnumerable<T> List<T>.Enumeratorในบริบทส่วนใหญ่ประเภทนั้นจะให้ประสิทธิภาพที่ดีขึ้นเล็กน้อยกว่าวัตถุฮีปแบบสแตนด์อโลน คอมไพเลอร์ซึ่งตัวแจงนับชนิดเป็ด (ทั้ง C # และ vb.net ทำ) สามารถใช้ประโยชน์จากสิ่งนี้เมื่อสร้างforeachรหัส ถ้าList<T>จะโยนไปIEnumrable<T>ก่อนforeachที่IEnumerable<T>.GetEnumerator()วิธีการที่จะกลับมาเป็นวัตถุกองจัดสรร, การแสดงผลเพิ่มประสิทธิภาพเป็นไปไม่ได้
supercat

85

ICollection<T>ถูกใช้เนื่องจากIEnumerable<T>อินเตอร์เฟสไม่มีวิธีในการเพิ่มไอเท็มการลบไอเท็มหรือการแก้ไขการรวบรวม


3
สิ่งที่เกี่ยวกับการเปรียบเทียบกับรายการ <T>
Jan Carlo Viray

12
List<T>ICollection<T>การดำเนินการ
อะไรต่อมิอะไร

ไม่ใช่แบบทั่วไปICollectionไม่อนุญาตให้มีวิธีการเพิ่มรายการใด ๆ แต่ก็ยังเป็นประโยชน์เสริมIEnumerable<T>เพราะมันให้Countสมาชิกซึ่งโดยทั่วไปจะเร็วกว่าการแจกแจงทุกอย่าง หมายเหตุว่าถ้าIList<Cat>หรือICollection<Cat>ถูกส่งไปยังรหัสคาดหวังว่าIEnumerable<Animal>การCount()วิธีขยายจะเร็วถ้ามันดำเนินการที่ไม่ได้ทั่วไปICollectionแต่ไม่ถ้ามันใช้อินเตอร์เฟซทั่วไปตั้งแต่ทั่วไปจะไม่ดำเนินการICollection<Cat> ICollection<Animal>
supercat

58

ตอบคำถามของคุณเกี่ยวกับList<T>:

List<T>เป็นคลาส; การระบุอินเทอร์เฟซทำให้มีความยืดหยุ่นในการใช้ คำถามที่ดีกว่าคือ "ทำไมไม่IList<T>"

ในการตอบคำถามนั้นให้พิจารณาสิ่งที่IList<T>เพิ่มไปที่ICollection<T>: การจัดทำดัชนีจำนวนเต็มซึ่งหมายความว่ารายการนั้นมีคำสั่งโดยพลการบางอย่างและสามารถดึงข้อมูลได้โดยอ้างอิงไปยังลำดับนั้น นี่อาจไม่ได้มีความหมายในกรณีส่วนใหญ่เนื่องจากรายการอาจต้องสั่งแตกต่างกันในบริบทที่แตกต่างกัน


21

มีความแตกต่างพื้นฐานระหว่าง ICollection และ IEnumerable

  • IEnumerable - มีเฉพาะเมธอด GetEnumerator เพื่อรับ Enumerator และอนุญาตการวนซ้ำ
  • ICollectionมีวิธีการเพิ่มเติม: เพิ่ม, ลบ, มี, นับ, คัดลอกไปยัง
  • ICollectionสืบทอดมาจาก IEnumerable
  • ด้วย ICollection คุณสามารถปรับเปลี่ยนคอลเลกชันโดยใช้วิธีการเช่นเพิ่ม / ลบ คุณไม่มีอิสระที่จะทำเช่นเดียวกันกับ IEnumerable

โปรแกรมง่าย ๆ :

using System;
using System.Collections;
using System.Collections.Generic;

namespace StackDemo
{
    class Program 
    {
        static void Main(string[] args)
        {
            List<Person> persons = new List<Person>();
            persons.Add(new Person("John",30));
            persons.Add(new Person("Jack", 27));

            ICollection<Person> personCollection = persons;
            IEnumerable<Person> personEnumeration = persons;

            // IEnumeration
            // IEnumration Contains only GetEnumerator method to get Enumerator and make a looping
            foreach (Person p in personEnumeration)
            {                                   
               Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);
            }

            // ICollection
            // ICollection Add/Remove/Contains/Count/CopyTo
            // ICollection is inherited from IEnumerable
            personCollection.Add(new Person("Tim", 10));

            foreach (Person p in personCollection)
            {
                Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);        
            }
            Console.ReadLine();

        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }
    }
}

13

ฉันจำได้ด้วยวิธีนี้:

  1. IEnumerable มีหนึ่งเมธอด GetEnumerator () ที่อนุญาตให้หนึ่งอ่านค่าในคอลเลกชัน แต่ไม่ได้เขียนลงไป ความซับซ้อนของการใช้ตัวแจงนับส่วนใหญ่ได้รับการดูแลโดยเราสำหรับแต่ละคำสั่งใน C # IEnumerable มีหนึ่งคุณสมบัติ: ปัจจุบันซึ่งส่งคืนองค์ประกอบปัจจุบัน

  2. ICollection ใช้ IEnumerable และเพิ่มคุณสมบัติเพิ่มเติมไม่กี่รายการที่การใช้งานมากที่สุดคือ Count ICollection เวอร์ชันทั่วไปใช้เมธอด Add () และ Remove ()

  3. IList ใช้ทั้ง IEnumerable และ ICollection และเพิ่มการเข้าถึงการจัดทำดัชนีจำนวนเต็มในรายการ (ซึ่งโดยทั่วไปไม่จำเป็นต้องใช้เนื่องจากการสั่งซื้อจะทำในฐานข้อมูล)


4
ขึ้นอยู่กับสิ่งที่คุณเขียน ICollection และ IList เหมือนกัน โปรดเพิ่มสิ่งที่เพิ่มไปยัง IList ที่ไม่มีอยู่ใน ICollection
เดิมพัน

ICollection VS IList, IList- เฉพาะส่วนต่อประสานใน System.Collection ที่มีฟังก์ชันทั้งหมดของ IEnumerable และ ICollection และฟังก์ชันเพิ่มเติม IList มีวิธีการแทรกและลบ ทั้งสองวิธียอมรับดัชนีในพารามิเตอร์ของพวกเขา ดังนั้นจึงสนับสนุนการดำเนินการตามดัชนีมากกว่าการรวบรวม
E.Meir

7

แนวคิดพื้นฐานของการใช้ICollectionคือการให้อินเทอร์เฟซสำหรับการเข้าถึงข้อมูลจำนวน จำกัด แบบอ่านอย่างเดียว ในความเป็นจริงคุณมีคุณสมบัติICollection.Count IEnumerableเหมาะสำหรับสายข้อมูลที่คุณอ่านจนถึงจุดตรรกะบางเงื่อนไขที่ระบุโดยผู้บริโภคหรือจนถึงจุดสิ้นสุดของการแจงนับ


14
TIL ที่ICollectionอ่านอย่างเดียวในขณะที่ICollection<T>ไม่อยู่
Carl G

2

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

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

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net- MVC แอพลิเคชัน


2

สิ่งที่ฉันได้ทำในมีที่ผ่านมาประกาศคอลเลกชันระดับชั้นของฉันโดยใช้IList<Class>, ICollection<Class>หรือIEnumerable<Class>(ถ้ารายการคงที่) ขึ้นอยู่กับว่าหรือไม่ฉันจะต้องทำจำนวนต่อไปนี้ในวิธีการในพื้นที่เก็บข้อมูลของฉันใด ๆการระบุการจัดเรียง / สั่งซื้อหรือปรับเปลี่ยน . เมื่อฉันต้องการแจกแจง (และอาจจะเรียงลำดับ) บนวัตถุจากนั้นฉันสร้าง temp List<Class>เพื่อทำงานกับคอลเลกชันภายในวิธี IEnumerable ฉันคิดว่าการฝึกฝนนี้จะมีผลก็ต่อเมื่อการรวบรวมมีขนาดค่อนข้างเล็ก แต่อาจเป็นแนวปฏิบัติที่ดีโดยทั่วไป idk โปรดแก้ไขให้ฉันด้วยหากมีหลักฐานว่าทำไมสิ่งนี้ถึงไม่เป็นการปฏิบัติที่ดี


0

ให้ลองคิดนอกกรอบด้วย / โดยลอจิกและทำความเข้าใจกับอินเทอร์เฟซทั้งสามในคำถามของคุณ:

เมื่อคลาสของอินสแตนซ์บางตัวใช้อินเทอร์เฟซ System.Collection.IEnumerable ดังนั้นในคำง่าย ๆ เราสามารถพูดได้ว่าอินสแตนซ์นี้มีทั้งแบบนับจำนวนและ iterable ซึ่งหมายความว่าอินสแตนซ์นี้อนุญาตให้วนซ้ำไป สำรวจ / วนซ้ำไอเท็มและองค์ประกอบทั้งหมดที่อินสแตนซ์นี้มี

ซึ่งหมายความว่านี่เป็นไปได้ที่จะระบุรายการและองค์ประกอบทั้งหมดที่อินสแตนซ์นี้มี

ทุกคลาสที่ใช้อินเทอร์เฟซ System.Collection.IEnumerable ยังใช้เมธอด GetEnumerator ที่ไม่มีอาร์กิวเมนต์และส่งคืนอินสแตนซ์ System.Collections.IEnumerator

อินสแตนซ์ของ System.Collections.IEnumerator อินเทอร์เฟซทำงานคล้ายกับตัววนซ้ำ c ++

เมื่อคลาสของอินสแตนซ์บางตัวใช้ส่วนต่อประสาน System.Collection.ICollection ในคำง่ายๆเราสามารถพูดได้ว่าอินสแตนซ์นี้คือชุดของสิ่งต่าง ๆ

รุ่นทั่วไปของอินเทอร์เฟซนี้เช่น System.Collection.Generic.ICollection เป็นข้อมูลที่มากกว่าเนื่องจากอินเทอร์เฟซทั่วไปนี้ระบุสิ่งที่ประเภทของสิ่งต่าง ๆ ในคอลเลกชันอย่างชัดเจน

นี่คือเหตุผลที่สมเหตุสมผลเหตุผลตรรกะและทำให้รู้สึกว่า System.Collections.ICollection อินเตอร์เฟสสืบทอดมาจาก System.Collections.IE อินเทอร์เฟซที่นับไม่ได้เพราะในทางทฤษฎีแล้วทุกคอลเลกชันก็มีทั้งที่นับได้และสามารถทำซ้ำได้และในทางทฤษฎี ในทุกคอลเลกชัน

ส่วนต่อประสาน System.Collections.ICollection หมายถึงคอลเลกชันแบบไดนามิก จำกัด ที่มีการเปลี่ยนแปลงซึ่งหมายความว่ารายการที่มีอยู่สามารถลบออกจากคอลเลกชันและรายการใหม่สามารถเพิ่มลงในคอลเลกชันเดียวกัน

สิ่งนี้อธิบายว่าทำไมส่วนต่อประสาน System.Collections.ICollection มีวิธีการ "เพิ่ม" และ "ลบ"

เนื่องจากอินสแตนซ์ของ System.Collections.Collection ส่วนต่อประสานนั้นเป็นคอลเลกชันที่ จำกัด ดังนั้นคำว่า "finite" จึงมีความหมายว่าคอลเลกชันของส่วนต่อประสานนี้ทุกครั้งจะมีจำนวนรายการและองค์ประกอบที่แน่นอนอยู่เสมอ

คุณสมบัติ Count of System.Collections.ICollection interface จะส่งคืนหมายเลขนี้

ส่วนต่อประสาน System.Collections.IEnumerable ไม่มีวิธีการและคุณสมบัติเหล่านี้ที่ส่วนต่อประสาน System.Collections.ICollection เนื่องจากมันไม่ได้ทำให้รู้สึกว่า System.Collections.IEnumerable จะมีวิธีการและคุณสมบัติเหล่านี้ที่ System.Collections.ICollection มี

ลอจิกยังบอกอีกว่าทุกตัวอย่างที่มีทั้งจำนวนและ iterable นั้นไม่จำเป็นต้องเป็นของสะสมและไม่จำเป็นต้องเปลี่ยนแปลง

เมื่อฉันพูดว่าเปลี่ยนแปลงได้ฉันหมายความว่าอย่าคิดทันทีว่าคุณสามารถเพิ่มหรือลบบางสิ่งออกจากสิ่งที่นับได้และสามารถทำซ้ำได้

ถ้าฉันเพิ่งสร้างลำดับที่แน่นอนของจำนวนเฉพาะเช่นลำดับที่ จำกัด ของจำนวนเฉพาะนี้เป็นตัวอย่างของ System.Collections.IE อินเทอร์เฟซที่นับไม่ได้เพราะตอนนี้ฉันสามารถไปหาจำนวนเฉพาะทั้งหมดในลำดับที่ จำกัด นี้ในลูปเดียว และทำสิ่งที่ฉันต้องการจะทำกับพวกเขาแต่ละคนเช่นการพิมพ์แต่ละรายการไปที่หน้าต่างคอนโซลหรือหน้าจอ แต่ลำดับที่ จำกัด ของจำนวนเฉพาะนี้ไม่ได้เป็นตัวอย่างของ System.Collections.Collections.Collections interface เพราะสิ่งนี้ไม่สมเหตุสมผล เพิ่มหมายเลขคอมโพสิตลงในลำดับที่ จำกัด ของจำนวนเฉพาะ

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

นอกจากนี้คุณอาจต้องการใช้โค้ดและเขียน "return return" ในเมธอด GetEnumerator ของอินเตอร์เฟส System.Collections.IEnumerable เพื่อสร้างหมายเลขเฉพาะและไม่จัดสรรอะไรบนฮีปหน่วยความจำแล้วมอบหมาย Garbage Collector (GC) ให้กับทั้งสอง deallocate และทำให้หน่วยความจำว่างจากฮีปนี้เพราะเห็นได้ชัดว่าเป็นการเสียหน่วยความจำระบบปฏิบัติการและลดประสิทธิภาพลง

การจัดสรรหน่วยความจำแบบไดนามิกและการจัดสรรคืนบนฮีปควรทำเมื่อเรียกใช้เมธอดและคุณสมบัติของ System.Collections.ICollection interface แต่ไม่ใช่เมื่อทำการเรียกใช้เมธอดและคุณสมบัติของ System.Collections.IEnumerable interface (แม้ว่า System.Collections.IEnumerable interface เท่านั้น) 1 เมธอดและคุณสมบัติ 0)

ตามสิ่งที่คนอื่นพูดในเว็บเพจสแต็คโอเวอร์โฟลว์อินเทอร์เฟซ System.Collections.IList จะแสดงถึงลำดับที่สามารถสั่งซื้อได้คอลเลกชันนี้และอธิบายว่าทำไมวิธีการของการทำงานของอินเตอร์เฟซ System.Collections.IList กับดัชนีในทางตรงกันข้ามกับเหล่านี้ของอินเตอร์เฟซ System.Collections.ICollection

ในระยะสั้น System.Collections.ICollection อินเตอร์เฟสไม่ได้หมายความว่าอินสแตนซ์ของมันสามารถสั่งซื้อได้ แต่อินเตอร์เฟส System.Collections.IList นั้นหมายความว่า

ชุดที่ถูกสั่งในเชิงทฤษฎีเป็นกรณีพิเศษของชุดที่ไม่มีการเรียงลำดับ

นอกจากนี้ยังสมเหตุสมผลและอธิบายว่าทำไมส่วนต่อประสาน System.Collections.IList จึงรับส่วนต่อประสาน System.Collections.ICollection

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