Мне часто хотелось большего выбора интерфейсов, связанных с коллекцией, особенно ICountableEnumerable и IReadableByIndex. Первый можно было бы добавить в дизайн .Net без добавления дополнительного кода разработчиками; первый, вероятно, потребовал бы добавления метода GetByIndex, чтобы избежать конфликтов с индексатором чтения / записи, присутствующим в полном IList, но ИМХО по-прежнему было бы полезным добавлением, поскольку это могло бы быть противоречивым.
В действительности, возможно, что объект может быть универсальным IList, но не очень хорошо применимым для ваших целей, потому что это может быть IList типа, который получен из ожидаемого вами типа. Например, если ваша процедура ожидала IEnumerable (Of Car), но ей был передан IList (Of HondaCivic), было бы неплохо, если бы вы могли использовать функцию чтения по индексу. Если IList (Of T) унаследован от IReadableByIndex (Of T), как описано выше, IList (Of HondaCivic) может быть преобразован в IReadableByIndex (Of Car). К сожалению, такое преобразование невозможно с интерфейсом чтения-записи.
Тем не менее, использование универсальной подпрограммы для обработки списка может позволить избежать ненужного преобразования даже в таком случае. Следующий короткий класс VB иллюстрирует:
Class GenericTest
Class myThing
Public Value As String
Sub New(ByVal X As String)
Value = X
End Sub
End Class
Class myDerived
Inherits myThing
Sub New(ByVal x As String)
MyBase.New(x)
End Sub
End Class
Shared Sub ReversePrint(Of T As myThing)(ByVal theList As IEnumerable(Of T))
Dim castAsList As IList(Of T) = TryCast(theList, IList(Of T))
If castAsList Is Nothing Then
castAsList = theList.ToList
Debug.Print("Converting to list")
Else
Debug.Print("List was good")
End If
For i As Integer = castAsList.Count - 1 To 0 Step -1
Debug.Print(castAsList(i).Value.ToString)
Next
End Sub
Shared Sub Test()
Dim myList As New List(Of myDerived)
For i As Integer = 1 To 5
myList.Add(New myDerived("Item " & i.ToString))
Next
ReversePrint(myList)
ReversePrint(Of myThing)(myList)
End Sub
End Class
Функция ReversePrint преобразует или преобразует IEnumerable в IList и выводит его в обратном порядке. Обратите внимание, что процедура действительно «ожидает» IEnumerable (Of myThing), но принимает ее параметр как IEnumerable (Of T). Таким образом, если компилятор знает, что он реализует IEnumerable (Of myDerived), он может предложить MyDerived в качестве параметра типа. При этом объект может быть приведен к IList (из MyDerived). Если кто-то не позволяет универсальному параметру соответствовать исходному объекту, объект будет нормально передаваться в подпрограмму, но попытка ty-type не будет работать, и, следовательно, будет необходимо преобразовать элемент в IList, соответствующий переданному параметр типа.
PS - Одним из пунктов моего списка желаний для .Net 5.0 была бы возможность для интерфейса указать реализацию по умолчанию метода для использования в случае, если класс, который должен реализовать метод не обеспечивает один. Это может позволить Microsoft иметь наследование IList от контравариантного интерфейса IReadableByIndex (и, возможно, ковариантных интерфейсов IWritableByIndex и IAppendable) без нарушения существующего кода.