代码之家  ›  专栏  ›  技术社区  ›  David Pfeffer

在运行时将Func<object,Task>转换为Func<T,Task>

  •  0
  • David Pfeffer  · 技术社区  · 9 年前

    我有一个 Func<object, Task> 。我试图将其作为参数传递给一个函数 Func<T, Task> 。我正在使用反射创建 MethodInfo 对于函数,以及 T 直到运行时才知道被填充。

    我如何通过反思做到这一点?

    2 回复  |  直到 9 年前
        1
  •  5
  •   Lucas Trzesniewski    9 年前

    不要 需要做任何特别的事情。

    Func<in T, out TResult> contravariant 在…上 T -它的输入参数,并且每个类型都继承自 object 这意味着你可以 铸造 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 });
    
        2
  •  1
  •   Amir Popovich    9 年前

    我会用 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;
            }
        }