在运行时将 Func<object, Task> 转换为 Func<T, Task>
Convert Func<object, Task> to Func<T, Task> at runtime
我有一个Func<object, Task>
。我正在尝试将它作为参数传递给采用 Func<T, Task>
的函数。我正在使用反射为函数创建一个 MethodInfo
,并且要填充的 T
直到运行时才知道。
如何使用反射来做到这一点?
您不需要做任何特别的事情。
Func<in T, out TResult>
is contravariant on T
- 它的输入参数,每个类型都继承自 object
,这意味着你可以 cast Func<object, Task>
到 Func<T, Task>
对于 任何引用类型 T
- 按原样传递它,它将正常工作。
现在,这不适用于值类型,因为它们需要预先 拆箱。
因此,如果您的 T
是值类型,则必须将其包装在另一个将执行转换的委托中。
一种简单的方法是定义包装器方法:
private static Func<T, TResult> CastFunc<T, TResult>(Func<object, TResult> fn)
=> param => fn(param);
然后通过反射创建委托:
var result = (Func<int, Task>)typeof(WrapperClass)
.GetMethod(nameof(CastFunc), BindingFlags.NonPublic | BindingFlags.Static)
.MakeGenericMethod(typeof(int), typeof(Task)).Invoke(null, new object[] { fn });
我会使用 MakeGenericMethod
进行反思
这是一个简单的例子:
public class Example
{
public void Start()
{
Func<object, Task> func = o => null;
object objFunc = func; // got it from a generic place as an object or something
Type type = objFunc.GetType().GetGenericArguments()[0]; // get T in runtime
var method = typeof(Example).GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(type);
var result = method.Invoke(this, new object[1] { func });
}
public int DoSomething<T>(Func<T, Task> input)
{
return 1;
}
}
我有一个Func<object, Task>
。我正在尝试将它作为参数传递给采用 Func<T, Task>
的函数。我正在使用反射为函数创建一个 MethodInfo
,并且要填充的 T
直到运行时才知道。
如何使用反射来做到这一点?
您不需要做任何特别的事情。
Func<in T, out TResult>
is contravariant on T
- 它的输入参数,每个类型都继承自 object
,这意味着你可以 cast Func<object, Task>
到 Func<T, Task>
对于 任何引用类型 T
- 按原样传递它,它将正常工作。
现在,这不适用于值类型,因为它们需要预先 拆箱。
因此,如果您的 T
是值类型,则必须将其包装在另一个将执行转换的委托中。
一种简单的方法是定义包装器方法:
private static Func<T, TResult> CastFunc<T, TResult>(Func<object, TResult> fn)
=> param => fn(param);
然后通过反射创建委托:
var result = (Func<int, Task>)typeof(WrapperClass)
.GetMethod(nameof(CastFunc), BindingFlags.NonPublic | BindingFlags.Static)
.MakeGenericMethod(typeof(int), typeof(Task)).Invoke(null, new object[] { fn });
我会使用 MakeGenericMethod
这是一个简单的例子:
public class Example
{
public void Start()
{
Func<object, Task> func = o => null;
object objFunc = func; // got it from a generic place as an object or something
Type type = objFunc.GetType().GetGenericArguments()[0]; // get T in runtime
var method = typeof(Example).GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(type);
var result = method.Invoke(this, new object[1] { func });
}
public int DoSomething<T>(Func<T, Task> input)
{
return 1;
}
}