อาร์เรย์ใน C # ใช้ IList <T> บางส่วนได้อย่างไร


99

ดังที่คุณทราบอาร์เรย์ใน C # ใช้IList<T>กับอินเทอร์เฟซอื่น ๆ อย่างไรก็ตามพวกเขาทำสิ่งนี้โดยไม่นำคุณสมบัติ Count ของIList<T>! อาร์เรย์มีคุณสมบัติความยาวเท่านั้น

นี่เป็นตัวอย่างที่ชัดเจนของ C # / NET ที่ละเมิดกฎของตัวเองเกี่ยวกับการใช้งานอินเทอร์เฟซหรือฉันทำอะไรพลาดไป?


2
ไม่มีใครบอกว่าArrayชั้นเรียนจะต้องเขียนด้วย C #!
user541686

Arrayเป็นคลาส "เวทมนตร์" ซึ่งไม่สามารถนำไปใช้ใน C # หรือภาษาอื่น ๆ ที่กำหนดเป้าหมาย. net แต่คุณลักษณะเฉพาะนี้มีอยู่ใน C #
CodesInChaos

คำตอบ:


81

คำตอบใหม่ในแง่ของคำตอบของฮันส์

ขอบคุณคำตอบที่ได้รับจากฮันส์เราจะเห็นว่าการใช้งานค่อนข้างซับซ้อนกว่าที่เราคิด ทั้งคอมไพลเลอร์และ 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
{
    // Explicit interface implementation
    void IFoo.M1() {}

    // Implicit interface implementation
    public void M2() {}
}

class Test    
{
    static void Main()
    {
        Foo foo = new Foo();

        foo.M1(); // Compile-time failure
        foo.M2(); // Fine

        IFoo ifoo = foo;
        ifoo.M1(); // Fine
        ifoo.M2(); // Fine
    }
}

5
ฉันคิดว่าคุณจะได้รับความล้มเหลวในการรวบรวมเวลาใน foo.M1 (); ไม่ใช่ foo.M2 ();
Kevin Aenmey

ความท้าทายคือการมีคลาสที่ไม่ใช่ทั่วไปเช่นอาร์เรย์ใช้ประเภทอินเทอร์เฟซทั่วไปเช่น IList <> ข้อมูลโค้ดของคุณไม่ทำเช่นนั้น
Hans Passant

@HansPassant: มันง่ายมากที่จะทำให้คลาสที่ไม่ใช่ทั่วไปใช้ประเภทอินเทอร์เฟซทั่วไป เรื่องเล็กน้อย ฉันไม่เห็นสิ่งที่บ่งชี้ว่านั่นคือสิ่งที่ OP กำลังถามถึง
Jon Skeet

4
@JohnSaunders: อันที่จริงฉันไม่เชื่อว่าก่อนหน้านี้มันไม่ถูกต้องเลย ฉันได้ขยายมันออกไปมากและอธิบายว่าเหตุใด CLR จึงถือว่าอาร์เรย์ผิดปกติ - แต่ฉันเชื่อว่าคำตอบของฉันเกี่ยวกับการใช้งานอินเทอร์เฟซที่ชัดเจนนั้นค่อนข้างถูกต้องมาก่อน คุณไม่เห็นด้วยในทางใด อีกครั้งรายละเอียดจะเป็นประโยชน์ (อาจอยู่ในคำตอบของคุณเองหากเหมาะสม)
Jon Skeet

1
@RBT: ใช่แม้ว่าจะมีความแตกต่างในการใช้งานCountแต่Addก็มักจะโยนเนื่องจากอาร์เรย์มีขนาดคงที่
Jon Skeet

86

ดังที่คุณทราบอาร์เรย์ใน C # ใช้งานIList<T>ร่วมกับอินเทอร์เฟซอื่น ๆ

อืมใช่ไม่ไม่จริง นี่คือการประกาศสำหรับคลาส Array ในกรอบงาน. NET 4:

[Serializable, ComVisible(true)]
public abstract class Array : ICloneable, IList, ICollection, IEnumerable, 
                              IStructuralComparable, IStructuralEquatable
{
    // etc..
}

ใช้ System.Collections.IList ไม่ใช่ System.Collections.Generic.IList <> มันทำไม่ได้ Array ไม่ใช่แบบทั่วไป เช่นเดียวกันกับอินเทอร์เฟซ IEnumerable <> และ ICollection <> ทั่วไป

แต่ CLR สร้างประเภทอาร์เรย์คอนกรีตได้ทันทีดังนั้นในทางเทคนิคจึงสามารถสร้างประเภทที่ใช้อินเทอร์เฟซเหล่านี้ได้ อย่างไรก็ตามไม่เป็นเช่นนั้น ลองใช้รหัสนี้ตัวอย่าง:

using System;
using System.Collections.Generic;

class Program {
    static void Main(string[] args) {
        var goodmap = typeof(Derived).GetInterfaceMap(typeof(IEnumerable<int>));
        var badmap = typeof(int[]).GetInterfaceMap(typeof(IEnumerable<int>));  // Kaboom
    }
}
abstract class Base { }
class Derived : Base, IEnumerable<int> {
    public IEnumerator<int> GetEnumerator() { return null; }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
}

การเรียก GetInterfaceMap () ล้มเหลวสำหรับประเภทอาร์เรย์คอนกรีตที่มี "ไม่พบอินเทอร์เฟซ" แต่การส่งไปยัง IEnumerable <> ใช้งานได้โดยไม่มีปัญหา

นี่คือการพิมพ์ที่หลอกลวงเหมือนเป็ด เป็นการพิมพ์แบบเดียวกับที่สร้างภาพลวงตาว่าค่าทุกประเภทมาจาก ValueType ซึ่งมาจาก Object ทั้งคอมไพเลอร์และ CLR มีความรู้พิเศษเกี่ยวกับประเภทอาร์เรย์เช่นเดียวกับประเภทของค่า คอมไพเลอร์เห็นความพยายามของคุณในการส่งไปยัง IList <> และพูดว่า "โอเคฉันรู้วิธีทำ!" และปล่อยคำสั่ง castclass IL CLR ไม่มีปัญหากับมัน แต่รู้วิธีจัดเตรียมการใช้งาน IList <> ที่ทำงานบนวัตถุอาร์เรย์พื้นฐาน มันมีความรู้ในตัวเกี่ยวกับคลาส System.SZArrayHelper ที่ซ่อนอยู่ซึ่งเป็นเครื่องห่อหุ้มที่ใช้อินเทอร์เฟซเหล่านี้

ซึ่งไม่ได้ทำอย่างชัดเจนเหมือนที่ทุกคนอ้างคุณสมบัติ Count ที่คุณถามถึงมีลักษณะดังนี้:

    internal int get_Count<T>() {
        //! Warning: "this" is an array, not an SZArrayHelper. See comments above
        //! or you may introduce a security hole!
        T[] _this = JitHelpers.UnsafeCast<T[]>(this);
        return _this.Length;
    }

ใช่คุณสามารถเรียกความคิดเห็นนั้นว่า "แหกกฎ" ได้อย่างแน่นอน :) เป็นอย่างอื่นที่มีประโยชน์ และซ่อนไว้อย่างดีเยี่ยมคุณสามารถตรวจสอบสิ่งนี้ได้ใน SSCLI20 ซึ่งเป็นการแจกจ่ายซอร์สที่ใช้ร่วมกันสำหรับ CLR ค้นหา "IList" เพื่อดูว่าการทดแทนประเภทเกิดขึ้นที่ใด สถานที่ที่ดีที่สุดในการดูการทำงานคือวิธี clr / src / vm / array.cpp, GetActualImplementationForArrayGenericIListMethod ()

การทดแทนแบบนี้ใน CLR ค่อนข้างไม่รุนแรงเมื่อเทียบกับสิ่งที่เกิดขึ้นในการฉายภาพภาษาใน CLR ที่อนุญาตให้เขียนโค้ดที่มีการจัดการสำหรับ WinRT (aka Metro) NET ประเภทหลัก ๆ จะถูกแทนที่ที่นั่น IList <> แมปกับ IVector <> ตัวอย่างเช่นชนิดที่ไม่มีการจัดการทั้งหมด ตัวเองทดแทน COM ไม่รองรับประเภททั่วไป

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


1
นั่นคือการประกาศสำหรับArrayคลาสซึ่งไม่ใช่ประเภทของอาร์เรย์ เป็นประเภทฐานสำหรับอาร์เรย์ อาร์เรย์เดียวมิติใน C # ไม่IList<T>ดำเนินการ และไม่ใช่ประเภททั่วไปอย่างแน่นอนสามารถใช้อินเตอร์เฟซทั่วไปแล้ว ... ที่ทำงานเพราะมีจำนวนมากที่แตกต่างกันประเภท - typeof(int[])! = typeof (String []) , so typeof (int []) `การดำเนินการIList<int>และการดำเนินการtypeof(string[]) IList<string>
Jon Skeet

2
@HansPassant: โปรดอย่าคิดว่าฉันต้องการ downvote บางสิ่งบางอย่างเพียงเพราะมันเป็นความไม่สงบ ความจริงยังคงอยู่ที่การให้เหตุผลของคุณทั้งสองผ่านArray(ซึ่งตามที่คุณแสดงเป็นคลาสนามธรรมดังนั้นจึงไม่สามารถเป็นประเภทของวัตถุอาร์เรย์ที่แท้จริงได้ ) และข้อสรุป (ที่ไม่ได้ใช้งานIList<T>) เป็น IMO ที่ไม่ถูกต้อง วิธีในการที่จะดำเนินการIList<T>เป็นเรื่องแปลกและน่าสนใจผมจะเห็นด้วย - แต่ที่หมดจดการดำเนินงานรายละเอียด การอ้างว่าT[]ไม่ใช้งานIList<T>เป็นการทำให้เข้าใจผิด IMO มันขัดกับข้อมูลจำเพาะและพฤติกรรมที่สังเกตได้ทั้งหมด
Jon Skeet

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

4
แล้วอย่างน้อยการลบตรรกะปลอมที่อ้างว่าอาร์เรย์ไม่สามารถใช้งานได้IList<T> เพราะ Arrayไม่ได้? ตรรกะนั้นเป็นส่วนใหญ่ของสิ่งที่ฉันไม่เห็นด้วย นอกเหนือจากนั้นฉันคิดว่าเราต้องเห็นด้วยกับคำจำกัดความของความหมายของประเภทที่จะใช้อินเทอร์เฟซ: ตามความคิดของฉันประเภทอาร์เรย์จะแสดงคุณสมบัติที่สังเกตได้ทั้งหมดของประเภทที่นำไปใช้IList<T>นอกเหนือGetInterfaceMappingจาก อีกครั้งวิธีที่ประสบความสำเร็จนั้นมีความสำคัญน้อยกว่าสำหรับฉันเช่นเดียวกับฉันสบายดีที่พูดว่าSystem.Stringไม่เปลี่ยนรูปแม้ว่ารายละเอียดการใช้งานจะแตกต่างกัน
Jon Skeet

1
แล้วคอมไพเลอร์ C ++ CLI ล่ะ? เห็นได้ชัดว่ามีคนพูดว่า"ฉันไม่รู้จะทำยังไง!" และแจ้งข้อผิดพลาด ต้องมีการแคสต์อย่างชัดเจนถึงIList<T>จะทำงานได้
Tobias Knauss

21

IList<T>.Countถูกนำไปใช้อย่างชัดเจน :

int[] intArray = new int[10];
IList<int> intArrayAsList = (IList<int>)intArray;
Debug.Assert(intArrayAsList.Count == 10);

สิ่งนี้ทำได้เพื่อที่เมื่อคุณมีตัวแปรอาร์เรย์ธรรมดาคุณจะไม่มีทั้งสองอย่างCountและLengthพร้อมใช้งานโดยตรง

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

แก้ไข : อ๊ะจำไม่ได้ที่นั่น ICollection.Countถูกนำไปใช้อย่างชัดเจน ทั่วไปIList<T>มีการจัดการเป็นฮันส์ descibes ด้านล่าง


4
ทำให้ฉันสงสัยว่าทำไมพวกเขาถึงไม่เรียกคุณสมบัตินับแทนความยาว Array เป็นคอลเล็กชันทั่วไปเพียงรายการเดียวที่มีคุณสมบัติดังกล่าว (เว้นแต่คุณจะนับstring)
Tim S.

5
@TimS คำถามที่ดี (และเป็นคำถามที่ฉันไม่รู้) ฉันคาดเดาได้ว่าสาเหตุเป็นเพราะ "count" หมายถึงจำนวนรายการในขณะที่อาร์เรย์มี "ความยาว" ที่เปลี่ยนแปลงไม่ได้ทันทีที่มีการจัดสรร ( ไม่ว่าองค์ประกอบใดจะมีค่าก็ตาม)
dlev

1
@TimS ฉันคิดว่าเสร็จแล้วเพราะICollectionประกาศCountและมันจะยิ่งสับสนมากขึ้นถ้าไม่ได้ใช้ประเภทที่มีคำว่า "collection" Count:) การตัดสินใจเหล่านี้มีการแลกเปลี่ยนเสมอ
dlev

4
@JohnSaunders: และอีกครั้ง ... เพียงแค่โหวตลงโดยไม่มีข้อมูลที่เป็นประโยชน์
Jon Skeet

5
@JohnSaunders: ฉันยังไม่มั่นใจ ฮันส์ได้อ้างถึงการใช้งาน SSCLI แต่ยังอ้างว่าประเภทอาร์เรย์ไม่ได้ใช้งานIList<T>แม้ว่าทั้งภาษาและข้อกำหนดของ CLI จะปรากฏในทางตรงกันข้ามก็ตาม ฉันกล้าพูดว่าวิธีการใช้งานอินเทอร์เฟซภายใต้ฝาครอบอาจซับซ้อน แต่ก็เป็นเช่นนั้นในหลาย ๆ สถานการณ์ คุณจะลงคะแนนคนที่บอกว่าSystem.Stringไม่เปลี่ยนรูปด้วยเพราะการทำงานภายในไม่แน่นอนหรือไม่? สำหรับวัตถุประสงค์ในทางปฏิบัติทั้งหมด - และแน่นอนเท่าที่เกี่ยวข้องกับภาษา C # - เป็นเรื่องที่ชัดเจนโดยนัย
Jon Skeet

10

ใช้อินเตอร์เฟซที่ชัดเจน ในระยะสั้นคุณประกาศว่ามันเหมือนหรือvoid IControl.Paint() { }int IList<T>.Count { get { return 0; } }


2

ไม่ต่างอะไรกับการใช้งานอินเทอร์เฟซที่ชัดเจนของ IList เพียงเพราะคุณใช้อินเทอร์เฟซไม่ได้หมายความว่าสมาชิกจะต้องปรากฏเป็นสมาชิกชั้นเรียน มันไม่ใช้สถานที่ให้บริการจำนวนนั้นมันก็ไม่ได้เปิดเผยไว้ใน X []


1

มีแหล่งอ้างอิง:

//----------------------------------------------------------------------------------------
// ! READ THIS BEFORE YOU WORK ON THIS CLASS.
// 
// The methods on this class must be written VERY carefully to avoid introducing security holes.
// That's because they are invoked with special "this"! The "this" object
// for all of these methods are not SZArrayHelper objects. Rather, they are of type U[]
// where U[] is castable to T[]. No actual SZArrayHelper object is ever instantiated. Thus, you will
// see a lot of expressions that cast "this" "T[]". 
//
// This class is needed to allow an SZ array of type T[] to expose IList<T>,
// IList<T.BaseType>, etc., etc. all the way up to IList<Object>. When the following call is
// made:
//
//   ((IList<T>) (new U[n])).SomeIListMethod()
//
// the interface stub dispatcher treats this as a special case, loads up SZArrayHelper,
// finds the corresponding generic method (matched simply by method name), instantiates
// it for type <T> and executes it. 
//
// The "T" will reflect the interface used to invoke the method. The actual runtime "this" will be
// array that is castable to "T[]" (i.e. for primitivs and valuetypes, it will be exactly
// "T[]" - for orefs, it may be a "U[]" where U derives from T.)
//----------------------------------------------------------------------------------------
sealed class SZArrayHelper {
    // It is never legal to instantiate this class.
    private SZArrayHelper() {
        Contract.Assert(false, "Hey! How'd I get here?");
    }

    /* ... snip ... */
}

โดยเฉพาะส่วนนี้:

ผู้มอบหมายงานต้นขั้วของอินเทอร์เฟซถือว่าเป็นกรณีพิเศษโหลด SZArrayHelper ค้นหาวิธีการทั่วไปที่เกี่ยวข้อง (จับคู่เพียง ชื่อวิธีการ)สร้างอินสแตนซ์สำหรับประเภทและดำเนินการ

(เน้นของฉัน)

แหล่งที่มา (เลื่อนขึ้น)

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