如何从可能实现 IEnumerable的对象中提取 MethodInfo.Invoke 参数

发布于 2025-01-11 22:56:06 字数 2190 浏览 0 评论 0原文

使用反射,我尝试在预期为某种类型的 IEnumerable 的对象上调用 Linq 方法 IEnumerable.FirstOrDefault() ,并返回结果对象。

我有以下类:

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

class MyOtherClass { }

这就是我尝试调用该方法并返回结果的方式:

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[] { });
}

我期望为此方法提供新的 MyClass 将返回新的 MyOtherClass,但它失败了,因为 methodInfo.Invoke 期望参数数组中有一个对象。

System.Reflection.TargetParameterCountException: '参数计数不匹配。'

我不知道要向此方法提供什么,也不知道我要提供什么,也不知道为什么我必须提供它。

如果我提供某些类型,则会出现以下异常:

System.ArgumentException:'Object of type 'System.RuntimeType'无法转换为类型'System.Collections.Generic.IEnumerable`1 [MyNamespace.MyOtherClass]'.'

其他线程似乎没有解决 MethodInfo 调用的问题,或者假定要提供的类型MakeGenericMethod 在设计时可用,或者将 MethodInfo.Invoke 的参数数组指定为 null 或空。

我欢迎任何帮助理解这个问题的帮助,并且假设我用于查找泛型类型作为类型参数提供给 MakeGenericMethod 的代码至少在功能上是正确的,我应该向 methodInfo.Invoke 提供什么,为什么?

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

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[] { ??? });

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

月下凄凉 2025-01-18 22:56:06

FirstOrDefault 是一个扩展方法,您需要将 this 作为参数传递

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

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

return methodInfo.Invoke(null, new object[] {objectThatIsExpectedToImplementIEnumerableT });
傻比既视感 2025-01-18 22:56:06

你根本不需要为此进行反思。 IEnumerable 继承自 IEnumerable,您可以使用 IEnumerable 获取 IEnumerable演员():

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

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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文