在运行时将 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 - 按原样传递它,它将正常工作。

Example

现在,这不适用于值类型,因为它们需要预先 拆箱

因此,如果您的 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;
        }
    }