คำตอบใหม่ในแง่ของคำตอบของฮันส์
ขอบคุณคำตอบที่ได้รับจากฮันส์เราจะเห็นว่าการใช้งานค่อนข้างซับซ้อนกว่าที่เราคิด ทั้งคอมไพลเลอร์และ CLR พยายามอย่างมากที่จะสร้างความรู้สึกว่าประเภทอาร์เรย์ใช้งานได้IList<T>
- แต่ความแปรปรวนของอาร์เรย์ทำให้ยุ่งยากกว่า ตรงกันข้ามกับคำตอบจาก Hans ประเภทอาร์เรย์ (แบบมิติเดียวและเป็นศูนย์) จะใช้คอลเลกชันทั่วไปโดยตรงเนื่องจากประเภทของอาร์เรย์เฉพาะใด ๆไม่ได้ System.Array
เป็นเพียงประเภทพื้นฐานของอาร์เรย์ หากคุณถามประเภทอาร์เรย์ว่ารองรับอินเทอร์เฟซใดบ้างจะมีประเภททั่วไป:
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
เอาท์พุต:
System.ICloneable
System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]
สำหรับอาร์เรย์แบบมิติเดียวที่ใช้ศูนย์เท่าที่เกี่ยวข้องกับภาษาอาร์เรย์ก็ใช้งานได้IList<T>
เช่นกัน ส่วน 12.1.2 ของข้อกำหนด C # กล่าวเช่นนั้น ดังนั้นไม่ว่าการนำไปใช้งานใด ๆ ก็ตามภาษาจะต้องทำงานเหมือนกับว่าเป็นประเภทของT[]
การใช้งานIList<T>
เช่นเดียวกับอินเทอร์เฟซอื่น ๆ จากมุมมองนี้อินเทอร์เฟซจะถูกนำไปใช้กับสมาชิกบางคนที่ถูกนำไปใช้อย่างชัดเจน (เช่นCount
) นั่นเป็นคำอธิบายที่ดีที่สุดในระดับภาษาสำหรับสิ่งที่เกิดขึ้น
โปรดทราบว่าสิ่งนี้มีไว้สำหรับอาร์เรย์แบบมิติเดียวเท่านั้น (และอาร์เรย์ที่ใช้ศูนย์ไม่ใช่ว่า C # เป็นภาษาพูดอะไรก็ได้เกี่ยวกับอาร์เรย์ที่ไม่อิงศูนย์) T[,]
ไม่ได้IList<T>
ดำเนินการ
จากมุมมองของ CLR มีบางสิ่งที่น่าสนุกกว่ากำลังเกิดขึ้น คุณไม่สามารถรับการแมปอินเทอร์เฟซสำหรับประเภทอินเทอร์เฟซทั่วไป ตัวอย่างเช่น:
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
ให้ข้อยกเว้น:
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
แล้วทำไมความแปลก? ฉันเชื่อว่ามันเกิดจากความแปรปรวนร่วมของอาร์เรย์ซึ่งเป็นหูดในระบบประเภท IMO แม้ว่าIList<T>
จะไม่ใช่ความแปรปรวนร่วม (และไม่สามารถปลอดภัยได้) ความแปรปรวนร่วมของอาร์เรย์ช่วยให้สิ่งนี้ทำงานได้:
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... ซึ่งจะทำให้มันมีลักษณะเหมือนtypeof(string[])
การดำเนินการIList<object>
เมื่อมันไม่จริง
ข้อมูลจำเพาะ CLI (ECMA-335) พาร์ติชัน 1 ส่วน 8.7.1 มีสิ่งนี้:
ลายเซ็นประเภท T เข้ากันได้กับลายเซ็นประเภท U ถ้ามีอย่างน้อยหนึ่งอย่างต่อไปนี้
...
T เป็นอาร์เรย์อันดับ 1 ที่ใช้V[]
ศูนย์และU
เป็นIList<W>
และ V คืออาร์เรย์องค์ประกอบที่เข้ากันได้กับ W
(ไม่ได้พูดถึงจริงICollection<W>
หรือIEnumerable<W>
ที่ฉันเชื่อว่าเป็นบั๊กในสเป็ค)
สำหรับความไม่แปรปรวนข้อมูลจำเพาะ CLI จะไปพร้อมกับข้อมูลจำเพาะของภาษาโดยตรง จากส่วน 8.9.1 ของพาร์ติชัน 1:
นอกจากนี้เวกเตอร์ที่สร้างขึ้นด้วยองค์ประกอบประเภท T ใช้อินเทอร์เฟซSystem.Collections.Generic.IList<U>
โดยที่ U: = T. (§8.7)
( เวกเตอร์คืออาร์เรย์มิติเดียวที่มีฐานเป็นศูนย์)
ตอนนี้ในแง่ของรายละเอียดการใช้งานเห็นได้ชัดว่า CLR กำลังทำแผนที่ที่ขี้ขลาดเพื่อรักษาความเข้ากันได้ของการมอบหมายไว้ที่นี่: เมื่อstring[]
ถูกขอให้นำไปใช้งานICollection<object>.Count
จะไม่สามารถจัดการได้ในลักษณะปกติ สิ่งนี้นับเป็นการใช้งานอินเทอร์เฟซที่ชัดเจนหรือไม่ ฉันคิดว่ามันสมเหตุสมผลที่จะปฏิบัติเช่นนั้นเว้นแต่คุณจะขอการแมปอินเทอร์เฟซโดยตรงมันมักจะทำงานในมุมมองของภาษา
เกี่ยวกับอะไรICollection.Count
?
จนถึงขณะนี้ผมได้พูดคุยเกี่ยวกับอินเตอร์เฟซทั่วไป แต่แล้วก็มีที่ไม่ได้ทั่วไปICollection
ด้วยCount
คุณสมบัติ เวลานี้เราสามารถSystem.Array
ได้รับการทำแผนที่อินเตอร์เฟซและอินเตอร์เฟซในความเป็นจริงจะดำเนินการโดยตรง เอกสารสำหรับการICollection.Count
ใช้งานคุณสมบัติในArray
สถานะที่ดำเนินการกับการใช้งานอินเทอร์เฟซที่ชัดเจน
หากใครสามารถนึกถึงวิธีที่การใช้งานอินเทอร์เฟซแบบโจ่งแจ้งประเภทนี้แตกต่างจากการใช้งานอินเทอร์เฟซที่ชัดเจน "ปกติ" เรายินดีที่จะตรวจสอบเพิ่มเติม
คำตอบเก่า ๆ เกี่ยวกับการใช้งานอินเทอร์เฟซที่ชัดเจน
แม้จะมีการข้างต้นซึ่งมีความซับซ้อนมากขึ้นเพราะความรู้ของอาร์เรย์ที่คุณยังสามารถทำบางสิ่งบางอย่างแบบเดียวกับที่มองเห็นผลกระทบผ่านการใช้อินเตอร์เฟซที่ชัดเจน
นี่คือตัวอย่างแบบสแตนด์อโลนง่ายๆ:
public interface IFoo
{
void M1();
void M2();
}
public class Foo : IFoo
{
void IFoo.M1() {}
public void M2() {}
}
class Test
{
static void Main()
{
Foo foo = new Foo();
foo.M1();
foo.M2();
IFoo ifoo = foo;
ifoo.M1();
ifoo.M2();
}
}
Array
ชั้นเรียนจะต้องเขียนด้วย C #!