2015-08-12 3 views
0

У меня есть Func<object, Task>. Я пытаюсь передать его как аргумент в функцию, которая принимает Func<T, Task>. Я использую рефлексию для создания функции MethodInfo, а заполняемый T не известен до выполнения.Преобразование Func <объект, задача> в Func <T, Task> во время выполнения

Как я могу это сделать с отражением?

ответ

5

Вы не необходимо сделать что-нибудь особенное.

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 }); 
+0

Дох. Я полностью пропустил это. –

1

Я бы для отражения с помощью 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; 
     } 
    } 
Смежные вопросы