How to dynamically call a common extension method?

I wrote this extension method:

public static DataTable ToDataTable<T>(this IList<T> list) {...} 

Works well if called with a type known at compile time:

 DataTable tbl = new List<int>().ToDataTable(); 

But what should I call it if the generic type is unknown?

 object list = new List<int>(); ... tbl = Extension.ToDataTable((List<object>)list); // won't work 
+6
generics c # extension-methods
source share
2 answers

This is because the List<int> not a List<object> - the List type is not covariant in its element type parameter. Unfortunately, you will need to get a typed version of the general method and call it using reflection:

 Type listItemType = typeof(int); // cheating for simplicity - see below for real approach MethodInfo openMethod = typeof(Extension).GetMethod("ToDataTable", ...); MethodInfo typedMethod = openMethod.MakeGenericMethod(typeof(listItemType)); typedMethod.Invoke(null, new object[] { list }); 

An alternative would be to create a version of your extension method that accepts IList , not IList<T> . The List<T> class implements this non-generic interface, as well as a generic interface, so you can call:

 public static DataTable WeakToDataTable(this IList list) { ... } ((IList)list).WeakToDataTable(); 

(Actually, you would probably use overloading rather than a different name, just using a different name to call different types.)


Additional information: In the reflection solution, I missed the problem of determining the type of the list item. It can be a little trickier depending on how sophisticated you are. If you assume that the object will be List<T> (for some T), then it is easy:

 Type listItemType = list.GetType().GetGenericArguments()[0]; 

If you are only ready to accept IList<T> , then this is a little more complicated, because you need to find the appropriate interface and get a general argument from this. And you cannot use GetInterface () because you are looking for a private, configured instance of a generic interface. Thus, you should be familiar with all the interfaces that are looking for an instance of IList<T> :

 foreach (Type itf in list.GetType().GetInterfaces()) { if (itf.IsGenericType && itf.GetGenericTypeDefinition == typeof(IList<>)) // note generic type definition syntax { listItemType = itf.GetGenericArguments()[0]; } } 

This will work for empty lists, since it is disconnected from the metadata, not the contents of the list.

+9
source share

After I had problems working with the IList<T> interface, I decided to use it using the IList interface, for example itowlson . This is a little ugly due to the _T method, but it works well:

 DataTable tbl = ((IList)value).ToDataTable(); public static class Extensions { private static DataTable ToDataTable(Array array) {...} private static DataTable ToDataTable(ArrayList list) {...} private static DataTable ToDataTable_T(IList list) {...} public static DataTable ToDataTable(this IList list) { if (list.GetType().IsArray) { // handle arrays - int[], double[,] etc. return ToDataTable((Array)list); } else if (list.GetType().IsGenericType) { // handle generic lists - List<T> etc. return ToDataTable_T(list); } else { // handle non generic lists - ArrayList etc. return ToDataTable((ArrayList)list); } } } 
0
source share

All Articles