将 lambda 作为参数分配给通过反射调用的泛型方法
Assigning a lambda as a parameter to a generic method called through reflection
考虑如下通用方法:
class SomeClass
{
public static void SomeMethod<T>(Func<T>);
}
我想使用反射来调用这个方法。这是我能做到的程度:
_SomeMethod = typeof(SomeClass).GetMethod("SomeMethod",
BindingFlags.Public | BindingFlags.Static);
Type type = typeof(SomeType); //Actually SomeType is extracted using reflection and it's not fixed
MethodInfo toBeCalled = _SomeMethod.MakeGenericMethod(type);
object obj = Activator.CreateInstance(type);
toBeCalled.Invoke(null, () => obj);
但是编译报错:
Error CS1660: Cannot convert `lambda expression' to non-delegate type `object' (CS1660)
哪个是绝对可以接受的,但有什么解决办法?
请记住,使用 lambda 创建的 closure 是我需要的东西,所以不要删除它。
[更新]
澄清情况,使之有道理;使用 lambda 创建的仿函数是 SomeMethod
用来创建 class SomeType
实例的实例化器。但我不想在仿函数中实际创建对象,而是 return 从之前的实例化对象集合中创建它。最简单的方法是将 obj
放在由 lambda 编辑的闭包 return 中,你不觉得吗?
简化为最简单的形式,我们有:
void Main()
{
MethodInfoInvoke(()=> {} );
}
void MethodInfoInvoke(object func)
{
}
失败并出现同样的错误。
现在,如果我们在委托中传递 lambda,似乎更快乐:
void Main()
{
Object obj = new Object();
Func<object> action = ()=> obj; ;
MethodInfoInvoke(action); // accepted!
}
我认为您希望通过采用 Func<T>
且 "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});
}
示例用法:
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);
或者,您可以构建表达式并编译成函数,如 所示。
听起来您并不真的需要此处的 lambda 表达式。您可以使用表达式树非常轻松地构建一个 return 常量值的函数:
var expression = Expression.Constant(obj, type);
var delegateType = typeof(Func<>).MakeGenericType(type);
var func = Expression.Lambda(delegateType, expression).Compile();
toBeCalled.Invoke(null, func);
考虑如下通用方法:
class SomeClass
{
public static void SomeMethod<T>(Func<T>);
}
我想使用反射来调用这个方法。这是我能做到的程度:
_SomeMethod = typeof(SomeClass).GetMethod("SomeMethod",
BindingFlags.Public | BindingFlags.Static);
Type type = typeof(SomeType); //Actually SomeType is extracted using reflection and it's not fixed
MethodInfo toBeCalled = _SomeMethod.MakeGenericMethod(type);
object obj = Activator.CreateInstance(type);
toBeCalled.Invoke(null, () => obj);
但是编译报错:
Error CS1660: Cannot convert `lambda expression' to non-delegate type `object' (CS1660)
哪个是绝对可以接受的,但有什么解决办法?
请记住,使用 lambda 创建的 closure 是我需要的东西,所以不要删除它。
[更新]
澄清情况,使之有道理;使用 lambda 创建的仿函数是 SomeMethod
用来创建 class SomeType
实例的实例化器。但我不想在仿函数中实际创建对象,而是 return 从之前的实例化对象集合中创建它。最简单的方法是将 obj
放在由 lambda 编辑的闭包 return 中,你不觉得吗?
简化为最简单的形式,我们有:
void Main()
{
MethodInfoInvoke(()=> {} );
}
void MethodInfoInvoke(object func)
{
}
失败并出现同样的错误。
现在,如果我们在委托中传递 lambda,似乎更快乐:
void Main()
{
Object obj = new Object();
Func<object> action = ()=> obj; ;
MethodInfoInvoke(action); // accepted!
}
我认为您希望通过采用 Func<T>
且 "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});
}
示例用法:
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);
或者,您可以构建表达式并编译成函数,如
听起来您并不真的需要此处的 lambda 表达式。您可以使用表达式树非常轻松地构建一个 return 常量值的函数:
var expression = Expression.Constant(obj, type);
var delegateType = typeof(Func<>).MakeGenericType(type);
var func = Expression.Lambda(delegateType, expression).Compile();
toBeCalled.Invoke(null, func);