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 });