Casting an IEnumerable to IEnumerable with refl

2019-09-07 04:37发布

问题:

So, I need to call a third party method, that has a signature like this

ThirdPartyMethod<T>(IEnumerable<T> items)

My problem is I don't know the type of my object at compile time.

At compile time I have this

IEnumerable myObject;
Type typeOfEnumerableIHave;

Sooo..can reflection help me out here somehow?

for simplicity sake, pretend I have a method like this

void DoWork(IEnumerable items, Type type)
{
   //In here I have to call ThirdPartyMethod<T>(IEnumerable<T> items);
}

回答1:

Since you have IEnumerable myObject; and signature like ThirdPartyMethod<T>(IEnumerable<T> items) you are able to use Cast():

ThirdPartyMethod(myObject.Cast<T>())

If you don't know the T type at the compile time you should provide it at runtime.

Consider you third-party library looks like this

public static class External
{
    public static void ThirdPartyMethod<T>(IEnumerable<T> items)
    {
        Console.WriteLine(typeof(T).Name);
    }
}

if you have following

Type theType = typeof(int); 
IEnumerable myObject = new object[0];

you can get generic methods ThirdPartyMethod and Cast at the runtime

var targetMethod = typeof(External).GetMethod("ThirdPartyMethod", BindingFlags.Static | BindingFlags.Public);
var targetGenericMethod = targetMethod.MakeGenericMethod(new Type[] { theType });

var castMethod = typeof(Enumerable).GetMethod("Cast", BindingFlags.Static | BindingFlags.Public);
var caxtGenericMethod = castMethod.MakeGenericMethod(new Type[] { theType });

Finally you call the method:

targetGenericMethod.Invoke(null, new object[] { caxtGenericMethod.Invoke(null, new object[] { myObject }) });


回答2:

You could try something like this:

void DoWork(IEnumerable items, Type type)
    {
        // instance of object you want to call
        var thirdPartyObject = new ThirdPartyObject();
        // create a list with type "type"
        var typeOfList = typeof(List<>).MakeGenericType(type);
        // create an instance of the list and set items 
        // as constructor parameter
        var listInstance = Activator.CreateInstance(listOfTypes, items);
        // call the 3. party method via reflection, make it generic and
        // provide our list instance as parameter
        thirdPartyObject.GetType().GetMethod("ThirdPartyMethod")
            .MakeGenericMethod(type)
            .Invoke(thirdPartyObject, new []{listInstance});            
    }

The code creates a list instance of the generic type "type" (by using MakeGenericType). Your item elements are then copied to the list and the third party method is called via relection (note the "MakeGenericMethod" call to ensure that the method has the same type parameter as the method argument.