C# 将lambda作为参数指定给通过反射调用的泛型方法

C# 将lambda作为参数指定给通过反射调用的泛型方法,c#,generics,reflection,lambda,closures,C#,Generics,Reflection,Lambda,Closures,考虑以下通用方法: class SomeClass { public static void SomeMethod<T>(Func<T>); } 但它给出了编译错误: Error CS1660: Cannot convert `lambda expression' to non-delegate type `object' (CS1660) 这是绝对可以接受的,但有什么解决办法 请记住,使用lambda创建的闭包是我需要的,所以不要消除它 [更新] 澄清情况,

考虑以下通用方法:

class SomeClass
{
    public static void SomeMethod<T>(Func<T>);
}
但它给出了编译错误:

Error CS1660: Cannot convert `lambda expression' to non-delegate type `object' (CS1660)
这是绝对可以接受的,但有什么解决办法

请记住,使用lambda创建的闭包是我需要的,所以不要消除它

[更新]


澄清情况,使其有意义;使用lambda创建的functor是
SomeMethod
用于创建类
SomeType
实例的实例化器。但我不想在functor中实际创建对象,而是从以前的实例化对象集合中返回它。最简单的方法是将
obj
放在lambda返回的闭包中,你不这样认为吗?

简化为最简单的形式,我们有:

void Main()
{
    MethodInfoInvoke(()=> {} );
}

void MethodInfoInvoke(object func)
{
}
它失败了,并且出现了同样的错误

现在,如果我们在一个委托中传递lambda,它似乎更快乐:

void Main()
{
    Object obj = new Object();
    Func<object> action = ()=> obj; ;
    MethodInfoInvoke(action);      // accepted!
}
void Main()
{
Object obj=新对象();
Func action=()=>obj;
MethodInfoInvoke(操作);//已接受!
}

我认为您希望将已知对象传递给采用
Func
且“Func”始终是标识的通用方法。多用一个包装器可能会有所帮助:

public void SomeMethodInvokerRuntime(Type typeofSomeClass, object obj)
{
    var _SomeMethod = this.GetType().GetMethod("SomeMethodInvoker", 
        BindingFlags.Public | BindingFlags.Static);
    MethodInfo toBeCalled = _SomeMethod.MakeGenericMethod(obj.GetType());
    toBeCalled.Invoke(null, new[]{typeofSomeClass, obj});
}

public static void SomeMethodInvoker<T>(Type typeofSomeClass, T obj)
{
    var _SomeMethod = typeofSomeClass.GetMethod("SomeMethod",
          BindingFlags.Public | BindingFlags.Static);
    MethodInfo toBeCalled = _SomeMethod.MakeGenericMethod(typeof(T));
    Func<T> that = () => obj; // Main part - strongly typed delegate
    toBeCalled.Invoke(null, new[]{that});
}
public void SomeMethodInvokerRuntime(someClass的类型,对象obj)
{
var\u SomeMethod=this.GetType().GetMethod(“SomeMethodInvoker”,
BindingFlags.Public | BindingFlags.Static);
MethodInfo toBeCalled=\u SomeMethod.MakeGenericMethod(obj.GetType());
Invoke(null,new[]{typeofSomeClass,obj});
}
公共静态void SomeMethodInvoker(someClass的类型,T obj)
{
var\u SomeMethod=typeofSomeClass.GetMethod(“SomeMethod”,
BindingFlags.Public | BindingFlags.Static);
MethodInfo toBeCalled=\u SomeMethod.MakeGenericMethod(typeof(T));
Func that=()=>obj;//主要部分-强类型委托
调用(null,new[]{that});
}
示例用法:

static class Test
{
    public static void SomeMethod<T>(Func<T> f)
    {
        Console.WriteLine((T)(f()));
    }
}

SomeMethodInvoker(typeof(Test), 3);
object obj = "test";

SomeMethodInvokerRuntime(typeof(Test), obj);
静态类测试
{
公共静态方法(函数f)
{
控制台写入线((T)(f());
}
}
SomeMethodInvoker(typeof(Test),3);
object obj=“测试”;
SomeMethodInvokerRuntime(类型(测试),obj);

或者,您可以构建表达式并编译成函数,如中所示。

听起来您并不真正需要lambda表达式。您可以使用表达式树构建一个函数以非常轻松地返回常量值:

var expression = Expression.Constant(obj, type);
var delegateType = typeof(Func<>).MakeGenericType(type);
var func = Expression.Lambda(delegateType, expression).Compile();
toBeCalled.Invoke(null, func);
var expression=expression.Constant(obj,类型);
var delegateType=typeof(Func)。MakeGenericType(type);
var func=Expression.Lambda(delegateType,Expression.Compile();
toBeCalled.Invoke(null,func);

那么,obj的类型是什么?如果您不知道所涉及的
t
,很难看到如何从lambda表达式创建
Func
。您总是只返回一个常量值,还是有时会有其他lambda表达式?更多信息将非常有用。@JonSkeet我已经更新了问题,但是您想创建一个总是返回
obj
Func
?没有比这更复杂的了,是吗?您说要保留闭包-这是否意味着您要在以后更改
obj
的值?再说一次,更清晰的说明会很有帮助。我们能改变
SomeMethod()
?@JamesCurran不,事实上
SomeMethod
属于一个库,我没有写它!你的降价不合适。您不能减少使用
SomeMethod(Func)
,引入这样一个方法并尝试使用lambda作为参数使用反射调用它,然后您就会看到问题。您当前的解决方案不起作用。PS如果OP正在寻找表达式的近似性,我可能会发布示例。问题是您有
typeofSomeClass
,但没有
tobj
T
需要在编译时设置,但我们直到运行时才知道它。@JamesCurran但您已经知道如何使用未知类型调用泛型函数(
MakeGenericMethod
在SomeMethodInvoker上,并传递
methodInfoOfSomeMethodInvoker.Invoke(null,obj)
),所以我假设唯一的问题是如何构建
Func
。。。这能提供完整的答案吗?忽略这个答案-乔恩·斯基特等待了足够长的时间:)并发布了很棒的答案。@AlexeiLevenkov我更喜欢你的答案。它更简单,更容易理解。谢谢
var expression = Expression.Constant(obj, type);
var delegateType = typeof(Func<>).MakeGenericType(type);
var func = Expression.Lambda(delegateType, expression).Compile();
toBeCalled.Invoke(null, func);