Jawaban baru dalam terang jawaban Hans
Berkat jawaban yang diberikan oleh Hans, kita bisa melihat implementasinya agak lebih rumit dari yang kita kira. Baik compiler dan CLR berusaha keras untuk memberikan kesan bahwa sebuah tipe array diimplementasikan IList<T>
- tetapi varian array membuat ini lebih rumit. Bertentangan dengan jawaban dari Hans, tipe array (berdimensi tunggal, tetap saja berbasis nol) mengimplementasikan koleksi generik secara langsung, karena tipe dari array tertentu tidak System.Array
- itu hanya tipe dasar dari array. Jika Anda menanyakan tipe array apa antarmuka yang didukungnya, itu termasuk tipe generik:
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
Keluaran:
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]
Untuk larik berdimensi tunggal dan berbasis nol, sejauh menyangkut bahasanya , larik juga benar-benar diimplementasikan IList<T>
. Bagian 12.1.2 dari spesifikasi C # mengatakan demikian. Jadi, apa pun implementasi yang mendasarinya, bahasa tersebut harus berperilaku seolah-olah jenis T[]
implementasinya IList<T>
sama dengan antarmuka lainnya. Dari perspektif ini, antarmuka yang diimplementasikan dengan beberapa anggota yang secara eksplisit dilaksanakan (seperti Count
). Itulah penjelasan terbaik di tingkat bahasa untuk apa yang sedang terjadi.
Perhatikan bahwa ini hanya berlaku untuk larik berdimensi tunggal (dan larik berbasis nol, bukan karena C # sebagai bahasa mengatakan apa pun tentang larik berbasis non-nol). T[,]
tidak diimplementasikan IList<T>
.
Dari perspektif CLR, sesuatu yang lebih lucu sedang terjadi. Anda tidak bisa mendapatkan pemetaan antarmuka untuk tipe antarmuka generik. Sebagai contoh:
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
Memberikan pengecualian untuk:
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
Jadi kenapa anehnya? Yah, saya percaya itu benar-benar karena kovarians array, yang merupakan kutil dalam sistem tipe, IMO. Meskipun IList<T>
ini tidak kovarian (dan tidak dapat dengan aman), array kovarians memungkinkan ini bekerja:
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... yang membuatnya terlihat seperti typeof(string[])
alat IList<object>
, padahal sebenarnya tidak.
Spesifikasi CLI (ECMA-335) partisi 1, bagian 8.7.1, memiliki ini:
Jenis tanda tangan T kompatibel dengan jenis tanda tangan U jika dan hanya jika setidaknya salah satu dari yang berikut ini berlaku
...
T adalah array peringkat-1 berbasis nol V[]
, dan U
adalah IList<W>
, dan V kompatibel dengan elemen array-dengan W.
(Itu tidak benar-benar menyebutkan ICollection<W>
atau IEnumerable<W>
yang saya percaya adalah bug dalam spesifikasi.)
Untuk non-varians, spesifikasi CLI sejalan dengan spesifikasi bahasa secara langsung. Dari bagian 8.9.1 partisi 1:
Selain itu, vektor yang dibuat dengan tipe elemen T, mengimplementasikan antarmuka System.Collections.Generic.IList<U>
, di mana U: = T. (§8.7)
( Vektor adalah larik berdimensi tunggal dengan basis nol.)
Sekarang dalam hal detail implementasi , jelas CLR melakukan beberapa pemetaan yang funky untuk menjaga kompatibilitas penugasan di sini: ketika a string[]
diminta untuk implementasi ICollection<object>.Count
, CLR tidak dapat menanganinya dengan cara yang cukup normal. Apakah ini dihitung sebagai implementasi antarmuka eksplisit? Saya pikir masuk akal untuk memperlakukannya seperti itu, karena kecuali Anda meminta pemetaan antarmuka secara langsung, itu selalu berperilaku seperti itu dari perspektif bahasa.
Tentang apa ICollection.Count
?
Sejauh ini saya telah berbicara tentang antarmuka generik, tetapi kemudian ada antarmuka non-generik ICollection
dengan Count
propertinya. Kali ini kita bisa mendapatkan pemetaan antarmuka, dan ternyata antarmuka diimplementasikan langsung oleh System.Array
. Dokumentasi untuk ICollection.Count
implementasi properti dalam Array
status yang diimplementasikan dengan implementasi antarmuka eksplisit.
Jika ada yang dapat memikirkan cara di mana penerapan antarmuka eksplisit semacam ini berbeda dari penerapan antarmuka eksplisit "normal", saya akan dengan senang hati memeriksanya lebih jauh.
Jawaban lama seputar implementasi antarmuka eksplisit
Terlepas dari hal di atas, yang lebih rumit karena pengetahuan tentang array, Anda masih dapat melakukan sesuatu dengan efek terlihat yang sama melalui implementasi antarmuka eksplisit .
Berikut contoh mandiri sederhana:
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
}
}
Array
kelas harus ditulis dalam C #!