Hans'ın cevabının ışığında yeni cevap
Hans'ın verdiği cevap sayesinde uygulamanın düşündüğümüzden biraz daha karmaşık olduğunu görebiliyoruz. Hem derleyici hem de CLR , bir dizi türünün uyguladığı izlenimini vermek için çokIList<T>
çabalar - ancak dizi varyansı bunu daha zor hale getirir. Hans'ın cevabının tersine, dizi türleri (tek boyutlu, sıfır tabanlı) genel koleksiyonları doğrudan uygular, çünkü herhangi bir belirli dizinin türü değildir System.Array
- bu yalnızca dizinin temel türüdür. Bir dizi türüne hangi arabirimleri desteklediğini sorarsanız, genel türleri içerir:
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
Çıktı:
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]
Tek boyutlu, sıfır tabanlı diziler için, dil söz konusu olduğunda, dizi gerçekten de uygular IList<T>
. C # spesifikasyonunun 12.1.2 Bölümü öyle söylüyor. Bu nedenle, temel uygulama ne yaparsa yapsın, dil, başka herhangi bir arabirimde olduğu gibi uygulama türü gibi davranmalıdır . Bu açıdan bakıldığında, arayüz olan bazı üyelerinin açıkça (gibi uygulanıyor ile uygulanan ). Neler olup bittiğinin dil düzeyinde en iyi açıklaması budur.T[]
IList<T>
Count
Bunun yalnızca tek boyutlu diziler için geçerli olduğuna dikkat edin (ve sıfır tabanlı diziler, bir dil olarak C # 'ın sıfır tabanlı olmayan diziler hakkında bir şey söylediğini değil). T[,]
gelmez uygulamak IList<T>
.
CLR açısından daha eğlenceli bir şey oluyor. Genel arabirim türleri için arabirim eşlemesini alamazsınız. Örneğin:
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
Bir istisna verir:
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
Öyleyse neden tuhaflık? Bunun gerçekten, IMO tip sistemindeki bir siğil olan dizi kovaryansından kaynaklandığına inanıyorum. Olsa IList<T>
olduğu değil (ve güvenli olamaz) kovaryant, dizi kovaryans çalışmalarına bu sağlar:
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... bu da gerçekten olmadığında, alet gibi görünmesini sağlıyor .typeof(string[])
IList<object>
CLI spesifikasyonu (ECMA-335) bölüm 1, bölüm 8.7.1, şuna sahiptir:
Bir imza tipi T uyumludur - ancak ve ancak aşağıdaki durumlardan en az biri tutuyorsa U imza tipi ile uyumludur
...
T, bir sıfır temel seviye-1 dizidir V[]
ve U
olduğunu IList<W>
, ve V, W ile bir dizi element uyumlu-olduğu
(Aslında bahsetmiyor ICollection<W>
veya IEnumerable<W>
spesifikasyonda bir hata olduğuna inanıyorum.)
Varyans olmaması için, CLI spesifikasyonu doğrudan dil spesifikasyonuyla birlikte gider. Bölüm 1'in 8.9.1 bölümünden:
Ek olarak, öğe türü T ile oluşturulan bir vektör, arabirimi uygular System.Collections.Generic.IList<U>
, burada U: = T (§8.7)
(Bir vektör , sıfır tabanlı tek boyutlu bir dizidir.)
Şimdi, uygulama ayrıntıları açısından , CLR burada atama uyumluluğunu korumak için bazı ilginç haritalama yapıyor: a'nın string[]
uygulanması istendiğinde ICollection<object>.Count
, bunu oldukça normal bir şekilde halledemez . Bu, açık bir arayüz uygulaması olarak sayılır mı? Arayüz haritalamasını doğrudan istemediğiniz sürece, bu şekilde davranmanın mantıklı olduğunu düşünüyorum, her zaman dil açısından bu şekilde davranır .
Peki ya ICollection.Count
?
Şimdiye kadar jenerik arayüzlerden bahsettim, ancak bir de genel olmayan özelliği ICollection
ile birlikte var Count
. Bu sefer arayüz haritalamasını elde edebiliriz ve aslında arayüz doğrudan uygulanmaktadır System.Array
. ICollection.Count
Özellik uygulamasına yönelik belgeler Array
, açık arabirim uygulamasıyla uygulandığını belirtir.
Bu tür bir açık arabirim uygulamasının "normal" açık arabirim uygulamasından farklı olduğu bir yol düşünebilen biri varsa, onu daha ayrıntılı incelemekten memnuniyet duyarım.
Açık arabirim uygulamasıyla ilgili eski yanıt
Dizilerin bilgisi nedeniyle daha karmaşık olan yukarıdakilere rağmen, açık arabirim uygulaması yoluyla aynı görünür efektlerle bir şeyler yapabilirsiniz .
İşte basit bir bağımsız örnek:
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
sınıfın C # ile yazılması gerektiğini söylemedi !