如何使用 lambda 表达式作为参数通过反射调用方法?

发布于 2024-07-11 20:26:38 字数 470 浏览 3 评论 0原文

我想这样做:

MethodInfo m = myList.GetType().GetMethod("ConvertAll", System.Reflection.BindingFlags.InvokeMethod).MakeGenericMethod(typeof(object));
List<object> myConvertedList = (List<object>)m.Invoke(myList, new object[]{ (t => (object)t)});

myList是特定类型的通用列表(应用程序未知),我想将其转换为对象列表来执行一些操作。

但是,这会失败并出现以下错误:“无法将 lambda 表达式转换为类型“对象”,因为它不是委托类型”

您能帮我找出问题所在吗? 我是否正在尝试做一些不可能的事情?

还有其他方法可以实现同样的目的吗?

I want to do this:

MethodInfo m = myList.GetType().GetMethod("ConvertAll", System.Reflection.BindingFlags.InvokeMethod).MakeGenericMethod(typeof(object));
List<object> myConvertedList = (List<object>)m.Invoke(myList, new object[]{ (t => (object)t)});

myList is a generic list of a specific type (unknown to the application), and I want to convert it to a list of objects to do some operations.

However this fails with this error: "Cannot convert lambda expression to type 'object' because it is not a delegate type"

Can you help me find what's wrong? Am I trying to do something that's not possible?

Is there some other way to achieve the same thing?

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

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

发布评论

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

评论(2

盗琴音 2024-07-18 20:26:38

lambda 表达式可转换为委托类型或具有正确签名的表达式树 - 但您需要指定它是哪种委托类型。

我认为如果您将其设为通用方法,您的代码将会简单得多:

public static List<object> ConvertToListOfObjects<T>(List<T> list)
{
    return list.ConvertAll<object>(t => t);
}

然后您只需通用地查找并调用该方法:

MethodInfo method = typeof(Foo).GetMethod("ConvertToListOfObjects",
    BindingFlags.Static | BindingFlags.Public);
Type listType = list.GetType().GetGenericArguments()[0];
MethodInfo concrete = method.MakeGenericMethod(new [] { listType });
List<object> objectList = (List<object>) concrete.Invoke(null, 
                                                   new object[]{list});

完整示例:

using System;
using System.Reflection;
using System.Collections.Generic;

class Test
{
    public static List<object> ConvertToListOfObjects<T>(List<T> list)
    {
        return list.ConvertAll<object>(t => t);
    }

    static void Main()
    {
        object list = new List<int> { 1, 2, 3, 4 };

        MethodInfo method = typeof(Test).GetMethod("ConvertToListOfObjects",
            BindingFlags.Static | BindingFlags.Public);
        Type listType = list.GetType().GetGenericArguments()[0];
        MethodInfo concrete = method.MakeGenericMethod(new [] { listType });
        List<object> objectList = (List<object>) concrete.Invoke(null,
                                                    new object[] {list});

        foreach (object o in objectList)
        {
            Console.WriteLine(o);
        }
    }
}

A lambda expression is convertible to either a delegate type or an expression tree with the right signature - but you need to specify which delegate type it is.

I think your code would be much simpler if you made this a generic method:

public static List<object> ConvertToListOfObjects<T>(List<T> list)
{
    return list.ConvertAll<object>(t => t);
}

Then you just need to find and invoke that method generically:

MethodInfo method = typeof(Foo).GetMethod("ConvertToListOfObjects",
    BindingFlags.Static | BindingFlags.Public);
Type listType = list.GetType().GetGenericArguments()[0];
MethodInfo concrete = method.MakeGenericMethod(new [] { listType });
List<object> objectList = (List<object>) concrete.Invoke(null, 
                                                   new object[]{list});

Complete example:

using System;
using System.Reflection;
using System.Collections.Generic;

class Test
{
    public static List<object> ConvertToListOfObjects<T>(List<T> list)
    {
        return list.ConvertAll<object>(t => t);
    }

    static void Main()
    {
        object list = new List<int> { 1, 2, 3, 4 };

        MethodInfo method = typeof(Test).GetMethod("ConvertToListOfObjects",
            BindingFlags.Static | BindingFlags.Public);
        Type listType = list.GetType().GetGenericArguments()[0];
        MethodInfo concrete = method.MakeGenericMethod(new [] { listType });
        List<object> objectList = (List<object>) concrete.Invoke(null,
                                                    new object[] {list});

        foreach (object o in objectList)
        {
            Console.WriteLine(o);
        }
    }
}
芸娘子的小脾气 2024-07-18 20:26:38

lambda 形成一个方法组(基本上,这是仅通过名称(和范围)标识的方法。由于可以重载具有相同名称的方法,因此方法组包含多个不同的成员)。 这并不总是隐式转换为委托,因为委托实际上绑定到方法组中的单个方法。 这与过载有关。

不幸的是,这同样适用于您的情况。 补救措施是明确委托:

List<object> myConvertedList = (List<object>)m.Invoke(myList, new object[]{ new Func<YourType, object>(t => (object)t)});

A lambda forms a method group (basically this is a method identified by name (and scope) only. Since methods with the same name can be overloaded, a method group comprises several different members). This cannot always implicitly be converted to a delegate because a delegate is actually bound to a single method from within a method group. This plays a role with overloading.

Unfortunately, the same applies in your case. The remedy is to make an explicit delegate:

List<object> myConvertedList = (List<object>)m.Invoke(myList, new object[]{ new Func<YourType, object>(t => (object)t)});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文