MyClass[] array;
List<MyClass> list;
อะไรคือสถานการณ์สมมติเมื่อสถานการณ์หนึ่งดีกว่าอีกสถานการณ์หนึ่ง และทำไม?
MyClass[] array;
List<MyClass> list;
อะไรคือสถานการณ์สมมติเมื่อสถานการณ์หนึ่งดีกว่าอีกสถานการณ์หนึ่ง และทำไม?
คำตอบ:
ในความเป็นจริงมันเป็นของหายากที่คุณต้องการใช้อาร์เรย์ ใช้List<T>
ทุกครั้งที่คุณต้องการเพิ่ม / ลบข้อมูลอย่างแน่นอนเนื่องจากการปรับขนาดอาร์เรย์มีราคาแพง หากคุณทราบว่าข้อมูลมีความยาวคงที่และคุณต้องการปรับให้เหมาะสมขนาดเล็กด้วยเหตุผลเฉพาะบางอย่าง (หลังจากการเปรียบเทียบ) อาเรย์อาจมีประโยชน์
List<T>
ข้อเสนอจำนวนมากการทำงานมากขึ้นกว่าอาร์เรย์ (แม้ว่า LINQ ปรับขึ้นเล็กน้อย) และเป็นเกือบตลอดทางเลือกที่เหมาะสม ยกเว้นparams
ข้อโต้แย้งแน่นอน ;-P
ในฐานะเคาน์เตอร์ - List<T>
เป็นมิติเดียว; โดยที่คุณมีอาร์เรย์สี่เหลี่ยม (ฯลฯ ) เหมือนint[,]
หรือstring[,,]
- แต่มีวิธีอื่นในการสร้างแบบจำลองข้อมูลดังกล่าว (ถ้าคุณต้องการ) ในรูปแบบวัตถุ
ดูสิ่งนี้ด้วย:
ที่กล่าวว่าฉันใช้อาร์เรย์จำนวนมากในโครงการโปรโตบุฟสุทธิของฉัน ทั้งหมดเพื่อประสิทธิภาพ:
byte[]
จึงค่อนข้างจำเป็นสำหรับการเข้ารหัสbyte[]
บัฟเฟอร์กลิ้งท้องถิ่นซึ่งฉันกรอกก่อนที่จะส่งลงไปที่กระแสพื้นฐาน (และ vv); เร็วกว่าBufferedStream
ฯลฯFoo[]
แทนที่จะList<Foo>
) ภายในเนื่องจากขนาดจะถูกสร้างขึ้นครั้งเดียวและต้องเร็วมากแต่นี่เป็นข้อยกเว้นอย่างแน่นอน สำหรับการประมวลผลทั่วไปของธุรกิจการList<T>
ชนะทุกครั้ง
จริงๆแค่ตอบเพื่อเพิ่มลิงค์ที่ฉันประหลาดใจยังไม่ได้กล่าวถึง: บล็อกของ Eric Lippert ใน"อาร์เรย์ถือว่าค่อนข้างอันตราย"
คุณสามารถตัดสินจากชื่อที่แนะนำให้ใช้คอลเลกชันในทุกที่ที่ใช้งานได้ แต่ในขณะที่ Marc ชี้ให้เห็นอย่างถูกต้องมีสถานที่มากมายที่อาเรย์เป็นทางออกทางปฏิบัติเพียงอย่างเดียว
แม้จะมีคำตอบอื่น ๆ ที่แนะนำList<T>
คุณจะต้องใช้อาร์เรย์เมื่อจัดการ:
List<T>
ที่นี่มากกว่าอาร์เรย์ไบต์?
ถ้าคุณไม่เกี่ยวข้องกับประสิทธิภาพจริงๆและโดยที่ฉันหมายถึง "ทำไมคุณถึงใช้. Net แทน C ++" คุณควรติดกับ List <> ง่ายต่อการบำรุงรักษาและทำงานสกปรกทั้งหมดในการปรับขนาดอาร์เรย์เบื้องหลังสำหรับคุณ (หากจำเป็นรายการ <> ค่อนข้างฉลาดในการเลือกขนาดอาร์เรย์จึงไม่จำเป็นต้องทำตามปกติ)
ควรใช้อาร์เรย์ในการตั้งค่าเป็น List เมื่อความไม่สามารถเปลี่ยนแปลงได้ของคอลเลกชันเองเป็นส่วนหนึ่งของสัญญาระหว่างรหัสลูกค้าและผู้ให้บริการ
ตัวอย่างเช่น,
var str = "This is a string";
var strChars = str.ToCharArray(); // returns array
เป็นที่ชัดเจนว่าการดัดแปลงของ "strChars" จะไม่กลายพันธุ์วัตถุ "str" ดั้งเดิมโดยไม่คำนึงถึงความรู้ระดับการใช้งานของประเภทพื้นฐานของ "str"
แต่สมมติว่า
var str = "This is a string";
var strChars = str.ToCharList(); // returns List<char>
strChars.Insert(0, 'X');
ในกรณีนี้มันไม่ชัดเจนจากตัวอย่างโค้ดเพียงอย่างเดียวหากวิธีการแทรกจะหรือจะไม่กลายพันธุ์วัตถุ "str" ดั้งเดิม ต้องใช้ความรู้ระดับการใช้งานของ String เพื่อกำหนดซึ่งแบ่งการออกแบบตามสัญญา ในกรณีของ String ไม่ใช่เรื่องใหญ่ แต่เป็นเรื่องใหญ่ในเกือบทุกกรณี การตั้งค่ารายการเป็นแบบอ่านอย่างเดียวช่วยได้ แต่ส่งผลให้เกิดข้อผิดพลาดในการทำงานไม่ใช่การรวบรวม
To
กำลังจะสร้างวัตถุที่ไม่มีความสามารถในการปรับเปลี่ยนอินสแตนซ์ดั้งเดิมซึ่งตรงข้ามกับstrChars as char[]
ที่ถ้าถูกต้องจะแนะนำให้คุณสามารถแก้ไขวัตถุต้นฉบับ
str
ภายในใช้อาเรย์และToCharArray
ส่งกลับการอ้างอิงไปยังอาเรย์นี้ลูกค้าสามารถกลายพันธุ์ได้str
โดยการเปลี่ยนองค์ประกอบของอาเรย์นั้นแม้ว่าขนาดจะยังคงอยู่ แต่คุณเขียน 'เป็นที่ชัดเจนว่าการดัดแปลงของ "strChars" จะไม่กลายพันธุ์วัตถุ "str" ดั้งเดิม ฉันหายไปนี่อะไร จากสิ่งที่ฉันเห็นในทั้งสองกรณีลูกค้าอาจเข้าถึงการเป็นตัวแทนภายในและไม่ว่าจะเป็นประเภทใดก็ตามสิ่งนี้จะทำให้เกิดการกลายพันธุ์บางอย่าง
ถ้าฉันรู้ว่าวิธีการหลายองค์ประกอบที่ฉันจะต้องบอกว่าผมต้อง 5 องค์ประกอบและคนเดียวที่เคย 5 องค์ประกอบแล้วฉันจะใช้อาร์เรย์ มิฉะนั้นฉันจะใช้รายการ <T>
ส่วนใหญ่แล้วการใช้ a List
จะเพียงพอ A List
ใช้อาร์เรย์ภายในเพื่อจัดการข้อมูลและปรับขนาดอาร์เรย์โดยอัตโนมัติเมื่อเพิ่มองค์ประกอบเข้ากับList
ความจุปัจจุบันซึ่งทำให้ง่ายต่อการใช้งานมากกว่าอาร์เรย์ที่คุณต้องทราบความจุล่วงหน้า
ดูhttp://msdn.microsoft.com/en-us/library/ms379570(v=vs.80).aspx#datastructures20_1_topic5สำหรับข้อมูลเพิ่มเติมเกี่ยวกับรายชื่อใน C # System.Collections.Generic.List<T>
หรือเพียงแค่แยก
หากคุณต้องการข้อมูลหลายมิติ (ตัวอย่างเช่นการใช้เมทริกซ์หรือในการเขียนโปรแกรมกราฟิก) คุณอาจไปด้วยarray
แทน
เช่นเคยหากหน่วยความจำหรือประสิทธิภาพเป็นปัญหาให้วัดมัน! มิฉะนั้นคุณอาจตั้งสมมติฐานที่ผิดเกี่ยวกับรหัส
เทียบกับอาร์เรย์ รายการคือการบำรุงรักษาแบบคลาสสิกกับปัญหาด้านประสิทธิภาพ กฎง่ายๆที่นักพัฒนาเกือบทั้งหมดปฏิบัติตามคือคุณควรยิงให้ทั้งคู่ แต่เมื่อพวกเขาขัดแย้งกันให้เลือกความสามารถในการบำรุงรักษามากกว่าประสิทธิภาพ ข้อยกเว้นสำหรับกฎนั้นคือเมื่อประสิทธิภาพได้รับการพิสูจน์แล้วว่าเป็นปัญหา หากคุณนำหลักการนี้ไปใช้กับ Arrays กับ รายการสิ่งที่คุณได้รับคือ:
ใช้รายการที่พิมพ์อย่างมากจนกว่าคุณจะประสบปัญหาประสิทธิภาพการทำงาน หากคุณประสบปัญหาเกี่ยวกับประสิทธิภาพการตัดสินใจว่าการออกไปที่อาร์เรย์จะเป็นประโยชน์ต่อโซลูชันของคุณด้วยประสิทธิภาพมากกว่านั้นจะเป็นผลเสียต่อโซลูชันของคุณในแง่ของการบำรุงรักษาหรือไม่
อีกสถานการณ์ที่ยังไม่ได้กล่าวถึงคือเมื่อจะมีรายการจำนวนมากซึ่งแต่ละรายการประกอบด้วยตัวแปรที่เกี่ยวข้อง แต่ไม่เกี่ยวข้องกันติดอยู่ด้วยกัน (เช่นพิกัดของจุดหรือจุดยอดของรูปสามเหลี่ยมสามมิติ) อาร์เรย์ของโครงสร้างฟิลด์ที่เปิดเผยจะช่วยให้องค์ประกอบของมันสามารถแก้ไขได้อย่างมีประสิทธิภาพ "ในสถานที่" - สิ่งที่เป็นไปไม่ได้กับประเภทคอลเลกชันอื่น ๆ เนื่องจากอาเรย์ของโครงสร้างเก็บองค์ประกอบไว้อย่างต่อเนื่องในแรมการเข้าถึงลำดับของอิลิเมนต์เรียงลำดับจึงทำได้อย่างรวดเร็ว ในสถานการณ์ที่รหัสจะต้องมีการส่งผ่านลำดับจำนวนมากผ่านอาร์เรย์อาร์เรย์ของโครงสร้างอาจมีประสิทธิภาพสูงกว่าอาร์เรย์หรือคอลเลกชันอื่น ๆ ของการอ้างอิงวัตถุคลาสโดยปัจจัย 2: 1; เพิ่มเติม
แม้ว่าอาร์เรย์จะไม่สามารถปรับขนาดได้ แต่ก็ไม่ยากที่จะให้มีการอ้างอิงอาร์เรย์เก็บรหัสพร้อมกับจำนวนองค์ประกอบที่ใช้งานอยู่ อีกทางเลือกหนึ่งที่สามารถเขียนโค้ดได้อย่างง่ายดายสำหรับประเภทที่ประพฤติเหมือนList<T>
แต่สัมผัสการจัดเก็บการสนับสนุนของมันจึงช่วยให้หนึ่งที่จะพูดอย่างใดอย่างหนึ่งหรือMyPoints.Add(nextPoint);
MyPoints.Items[23].X += 5;
หมายเหตุที่หลังจะไม่จำเป็นต้องโยนยกเว้นถ้ารหัสพยายามที่จะเข้าถึงเกินสิ้นของรายการ List<T>
แต่การใช้งานมิฉะนั้นจะแนวคิดค่อนข้างคล้ายกับ
Point[] arr;
arr[3].x+=q;
ใช้เช่นมันจะเป็นสิ่งจำเป็นที่จะพูดแทนList<Point> list
Point temp=list[3]; temp.x+=q; list[3]=temp;
มันจะเป็นประโยชน์ถ้ามีวิธีการList<T>
Update<TP>(int index, ActionByRefRef<T,TP> proc, ref TP params)
และคอมไพเลอร์สามารถเปลี่ยนlist[3].x+=q;
เป็น{list.Update(3, (ref int value, ref int param)=>value+=param, ref q);
แต่ไม่มีคุณสมบัติดังกล่าวอยู่
list[0].X += 3;
จะเพิ่ม 3 เข้าไปในคุณสมบัติ X ขององค์ประกอบแรกของรายการ และlist
เป็นList<Point>
และPoint
เป็นคลาสที่มีคุณสมบัติ X และ Y
รายการใน. NET คือการล้อมรอบอาร์เรย์และใช้อาร์เรย์ภายใน ความซับซ้อนของเวลาของการดำเนินการกับรายการต่าง ๆ เหมือนกับที่มีในอาร์เรย์ แต่มีค่าใช้จ่ายเพิ่มขึ้นเล็กน้อยเมื่อใช้ฟังก์ชั่นที่เพิ่ม / ความสะดวกในการใช้งานรายการ (เช่นการปรับขนาดอัตโนมัติและวิธีการที่มาพร้อมกับรายการคลาส) สวยมากผมจะแนะนำให้ใช้รายการในทุกกรณีเว้นแต่จะมีเหตุผลที่น่าสนใจไม่ให้ทำเช่นนั้นเช่นถ้าคุณจำเป็นต้องเขียนโค้ดเพิ่มประสิทธิภาพมากหรือกำลังทำงานกับรหัสอื่น ๆ ที่ถูกสร้างขึ้นรอบอาร์เรย์
แทนที่จะเปรียบเทียบคุณสมบัติของข้อมูลแต่ละประเภทฉันคิดว่าคำตอบที่จริงจังที่สุดคือ "ความแตกต่างอาจไม่สำคัญสำหรับสิ่งที่คุณต้องทำให้สำเร็จโดยเฉพาะอย่างยิ่งเมื่อพวกเขานำมาใช้IEnumerable
ดังนั้นปฏิบัติตามอนุสัญญาที่เป็นที่นิยมและใช้List
จนกว่าคุณจะมีเหตุผลที่จะไม่ไปยังจุดที่คุณอาจจะมีเหตุผลในการใช้อาร์เรย์ของคุณมากกว่าList
"
เวลาส่วนใหญ่ในรหัสที่ได้รับการจัดการคุณจะต้องชื่นชอบคอลเลกชันที่ง่ายต่อการใช้งานมากที่สุดเท่าที่จะทำได้โดยไม่ต้องกังวลเกี่ยวกับการปรับให้เหมาะสมแบบไมโคร
พวกเขาอาจไม่เป็นที่นิยม แต่ฉันเป็นแฟนตัวยงของอาร์เรย์ในโครงการเกม - ความเร็วในการวนซ้ำอาจมีความสำคัญในบางกรณี foreach บน Array นั้นมีค่าใช้จ่ายน้อยลงอย่างมากถ้าคุณไม่ทำอะไรมากต่อองค์ประกอบ - การเพิ่มและลบออกไม่ได้ยากนักกับฟังก์ชันของผู้ช่วย - มันช้าลง แต่ในกรณีที่คุณสร้างมันเพียงครั้งเดียว มันอาจไม่สำคัญ - ในกรณีส่วนใหญ่หน่วยความจำเสริมน้อยกว่าจะสูญเปล่า (มีความสำคัญจริง ๆ กับอาร์เรย์ของ structs) - ขยะและตัวชี้และตัวชี้การไล่เล็กน้อยน้อยลง
ที่ถูกกล่าวว่าฉันใช้รายการบ่อยกว่าอาร์เรย์ในทางปฏิบัติ แต่พวกเขาแต่ละคนมีสถานที่ของพวกเขา
มันจะดีถ้ารายชื่อที่มีประเภทในตัวเพื่อให้พวกเขาสามารถเพิ่มประสิทธิภาพของเสื้อคลุมและค่าใช้จ่ายในการแจงนับ
การเติมรายการจะง่ายกว่าอาร์เรย์ สำหรับอาร์เรย์คุณจำเป็นต้องทราบความยาวของข้อมูลที่แน่นอน แต่สำหรับรายการขนาดข้อมูลอาจเป็นเท่าใดก็ได้ และคุณสามารถแปลงรายการเป็นอาร์เรย์
List<URLDTO> urls = new List<URLDTO>();
urls.Add(new URLDTO() {
key = "wiki",
url = "https://...",
});
urls.Add(new URLDTO()
{
key = "url",
url = "http://...",
});
urls.Add(new URLDTO()
{
key = "dir",
url = "https://...",
});
// convert a list into an array: URLDTO[]
return urls.ToArray();
เนื่องจากไม่มีใครพูดถึง: ใน C # อาร์เรย์เป็นรายการ MyClass[]
และList<MyClass>
ใช้งานทั้งสองIList<MyClass>
อย่าง (เช่นvoid Foo(IList<int> foo)
สามารถเรียกว่าชอบFoo(new[] { 1, 2, 3 })
หรือFoo(new List<int> { 1, 2, 3 })
)
ดังนั้นหากคุณกำลังเขียนวิธีการที่ยอมรับList<MyClass>
ว่าเป็นข้อโต้แย้ง แต่ใช้เพียงส่วนย่อยของคุณสมบัติคุณอาจต้องการประกาศเป็นIList<MyClass>
แทนเพื่อความสะดวกของผู้โทร
รายละเอียด:
List
เพียงใช้IList
อินเทอร์เฟซเท่านั้น
มันขึ้นอยู่กับบริบทที่ต้องการโครงสร้างข้อมูลอย่างสมบูรณ์ ตัวอย่างเช่นหากคุณกำลังสร้างไอเท็มที่จะใช้งานโดยฟังก์ชั่นหรือบริการอื่น ๆ ที่ใช้ List เป็นวิธีที่สมบูรณ์แบบในการทำให้สำเร็จ
ตอนนี้ถ้าคุณมีรายการของรายการและคุณต้องการที่จะแสดงพวกเขาพูดในแถวหน้าเว็บเป็นภาชนะที่คุณต้องใช้
IEnumerable<T>
- จากนั้นฉันสามารถสตรีมวัตถุมากกว่าบัฟเฟอร์พวกเขา
เป็นมูลค่าการกล่าวขวัญถึงความสามารถในการคัดเลือกนักแสดงทันที
interface IWork { }
class Foo : IWork { }
void Test( )
{
List<Foo> bb = new List<Foo>( );
// Error: CS0029 Cannot implicitly convert type 'System.Collections.Generic.List<Foo>' to 'System.Collections.Generic.List<IWork>'
List<IWork> cc = bb;
Foo[] bbb = new Foo[4];
// Fine
IWork[] ccc = bbb;
}
ดังนั้นArrayให้ความยืดหยุ่นมากขึ้นเล็กน้อยเมื่อใช้ในประเภทส่งคืนหรืออาร์กิวเมนต์สำหรับฟังก์ชัน
IWork[] GetAllWorks( )
{
List<Foo> fooWorks = new List<Foo>( );
return fooWorks.ToArray( ); // Fine
}
void ExecuteWorks( IWork[] works ) { } // Also accept Foo[]