Home > OS >  How to extract MethodInfo.Invoke parameters from an object maybe implementing IEnumerable<T>
How to extract MethodInfo.Invoke parameters from an object maybe implementing IEnumerable<T>

Time:03-06

Using reflection, I am trying to invoke Linq method IEnumerable.FirstOrDefault() on an object that is expected to be IEnumerable of some type, and return the result object.

I have the following classes:

class MyClass : IEnumerable<MyOtherClass>
{
    public IEnumerator<MyOtherClass> GetEnumerator() { yield return new MyOtherClass(); }
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

class MyOtherClass { }

This is how I attempted to invoke the method and return the result:

object GetFirstItemFromObject(object objectThatIsExpectedToImplementIEnumerableT) 
{
    Type genericType = 
        objectThatIsExpectedToImplementIEnumerableT
        .GetType()
        .GetInterfaces()
        .Where(@interface => @interface.Name == "IEnumerable`1")
        .FirstOrDefault()
        ?.GenericTypeArguments
        ?.First()
        ?? throw new ArgumentException("Object does not implement IEnumerable<T>.");

    var methodInfo = 
        typeof(Enumerable)
        .GetMethods(BindingFlags.Public | BindingFlags.Static)
        .Where(methodInfo1 => methodInfo1.Name == "FirstOrDefault")
        .Select(method => method.MakeGenericMethod(new[] { genericType }))
        .FirstOrDefault()
        ?? throw new ArgumentException("Object does not have method member FirstOrDefault.");

    return methodInfo.Invoke(objectThatIsExpectedToImplementIEnumerableT, new object[] { });
}

I expected that supplying a new MyClass to this method would return a new MyOtherClass, but it fails because methodInfo.Invoke expects a single object in the parameter array.

System.Reflection.TargetParameterCountException: 'Parameter count mismatch.'

I do not know what to supply to this method, or understand what I am supplying, or why I should have to supply it at all.

If I supply some type, I get the following exception:

System.ArgumentException: 'Object of type 'System.RuntimeType' cannot be converted to type 'System.Collections.Generic.IEnumerable`1[MyNamespace.MyOtherClass]'.'

Other threads seem not to address the question of a MethodInfo's invocation, or presume the type to supply to MakeGenericMethod is available at design time, or else give MethodInfo.Invoke's parameter array as null or empty.

I would welcome any help in understanding this problem and, assuming my code for finding the generic type to supply as type arguments to MakeGenericMethod is at least functionally correct, what I should supply to methodInfo.Invoke, and why?

return methodInfo.Invoke(objectThatIsExpectedToImplementIEnumerableT, new object[] { ??? });

CodePudding user response:

You don't need reflection at all for that. IEnumerable<T> inherits from IEnumerable, and you can get IEnumerable<object> from IEnumerable using Cast<T>():

object GetFirstItemFromObject(object objectThatIsExpectedToImplementIEnumerableT) 
{
    var enumerableObject = (IEnumerable)objectThatIsExpectedToImplementIEnumerableT;
    return enumerableObject.Cast<object>().FirstOrDefault();
}

CodePudding user response:

FirstOrDefault is an Extension method, you need to pass this as an arg

return methodInfo.Invoke(objectThatIsExpectedToImplementIEnumerableT, new object[] {objectThatIsExpectedToImplementIEnumerableT });
  • Related