Given an IEnumerable, how can I check if its type is List?
Given an IEnume开发者_JS百科rable, I want to perform List methods, but if it's a List already I will simply cast it rather that using .ToList()
Use the is
operator to test the type of the variable.
if(myIEnumerable is IList)
{
// it is a List (may still need casting in order to use List specific methods)
}
List list = (yourEnumerable as List) ?? yourEnumerable.ToList();
var myList = myIEnumerable as List ?? myIEnumerable.ToList();
or
var myList = (myIEnumerable as List<Type>) ?? myIEnumerable.ToList();
You can use is
or as
operators.
Couple of ways:
List<int> list = myColl as List<int>;
if (list != null) // ...
or
if (myColl is List<int>) // ...
or
if (myColl.GetType() == typeof(List<int>) // ...
I've often wished for a bigger selection of collection-related interfaces, especially ICountableEnumerable and IReadableByIndex. The former could have been added in the design of .Net without adding extra code by implementors; the former would probably have required the addition of a GetByIndex method to avoid conflicts with the read/write indexer present in a full IList, but would IMHO still have been a worthwhile addition since it could be contravariant.
As it is, it's possible that an object may be a generic IList but not very well usable for your purposes because it may be an IList of a type which is derived from the type you're expecting. For example, if your routine were expecting an IEnumerable(Of Car) but were passed an IList(Of HondaCivic), it would be nice if you could use its read-by-index function. If IList(Of T) inherited from IReadableByIndex(Of T), as described above, an IList(Of HondaCivic) could be cast to an IReadableByIndex(Of Car). Unfortunately, such a cast isn't possible with a read-write interface.
Still, using a generic routine to process the list may make it possible to avoid an unnecessary conversion even in such case. The following short VB class illustrates:
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
The ReversePrint function casts or converts an IEnumerable to an IList and outputs it in reverse order. Note that the routine is really "expecting" an IEnumerable(Of myThing), but accepts its parameter as an IEnumerable(Of T). Thus, if the compiler knows that it implements IEnumerable(Of myDerived), it can offer up MyDerived as a type parameter. When doing so, the object can be cast to an IList(of MyDerived). If one prevents the generic parameter from conforming to the original object, the object will be passed to the routine just fine, but the try-typecast won't work and thus it will be necessary to convert the item to an IList conforming to the passed-in type parameter.
PS--One of my wish-list items for .Net 5.0 would be the ability for an interface to specify a default implementation of a method for use in case a class which is supposed to implement a method doesn't provide one. This could allow Microsoft to have IList inherit from a contravariant IReadableByIndex interface (and possibly covariant IWritableByIndex and IAppendable interfaces) without breaking existing code.
精彩评论