Нова відповідь у світлі відповіді Ганса
Завдяки відповіді Ганса ми можемо бачити, що реалізація є дещо складнішою, ніж ми можемо подумати. І компілятор, і CLR дуже намагаються створити враження, що тип масиву реалізується IList<T>- але дисперсія масиву робить це складніше. На відміну від відповіді Ганса, типи масивів (одновимірні, на основі нуля все одно) реалізують загальні колекції безпосередньо, оскільки тип будь-якого конкретного масиву не є 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>, коли це не на самому ділі.
Розділ 8.7.1 специфікації CLI (ECMA-335), розділ 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
}
}
Arrayклас потрібно писати на C #!