如何动态创建一个Func<;T>;当T在C#中未知时

本文关键字:gt 未知 Func 动态 何动态 创建 一个 lt | 更新日期: 2023-09-27 18:20:38

我有一个返回值的任务,但我想将该值转换为其他值(例如,从string转换为int)。这通常很容易做到,我所做的只是添加继续任务,该任务完成转换并返回如下新类型:

ConverterService converter = ...;
Task<string> originalTask = Task.Factory.FromAsync<string>(...);
Task<int> conversionTask = originalTask.ContinueWith(p => converter.Convert(typeof(string), typeof(int), p.Result));

问题是类型未知:(我已经能够动态生成原始任务

ConverterService converter = ...;
// dynamically calling Task.Factory.FromAsync
var originalTask = FromAsyncMethodInfo.Invoke(Task.Factory, args.ToArray());
...
// now I want to dynamically call Task<string>.ContinueWith
var conversionTask = ContinueWithMethodInfo.Invoke(originalTask, ???)

我现在该怎么办?我希望为它提供一个Func<Task<T>, U>(在本例中实际上是Func<Task<string>, int>),但我如何动态生成它?

为了简单起见,我只想知道当我只有一个Type变量时,如何在运行时动态创建Func<T>。或者是第一块代码中看到的lambda的动态生成的替代方案:

Task<int> conversionTask = originalTask.ContinueWith(p => converter.Convert(typeof(string), typeof(int), p.Result));

非常感谢。

如何动态创建一个Func<;T>;当T在C#中未知时

我想你对自己到底需要什么有点困惑。。。根据您显示的代码,我认为您的Func必须返回object,并且您必须在任务执行后处理对象的强制转换。更进一步,如果您的Func包含确定返回类型的逻辑,那么您可以返回一个具有参数ReturnObjectReturnType的组合类MyResult,然后在执行后将ReturnObject强制转换为RetrunType对象。

您可以使用Task<object>并将项目作为object传递。您可以使用object.GetType()获取对象的类型。这里有一个例子:

void Main()
{
    var conversion = new ConversionService();
    var wantedType = typeof(string);
    Task<object> originalTask = Task<object>.Factory.StartNew(
       () => { /* test impl */ return 1; }); 
    var nextTask = originalTask.ContinueWith(prev =>
       conversion.ConvertObject(prev.Result.GetType(), wantedType, prev.Result));
    var result = nextTask.Result;
    Console.WriteLine("{0} - {1}", result.GetType(), result);
}
class ConversionService
{
    public object ConvertObject(Type source, Type dest, object input)
    {
        // test impl.
        return Convert.ChangeType(input, dest);
    }
}

您不能动态生成Func<TIn, TOut>,因为您需要提供用于进行转换的逻辑,并且在已知类型之前,您不能提供逻辑。

例如,如果您将int转换为string,您可以调用ToString(),而如果您朝着另一个方向前进,您可以使用int.TryParse()。如果您有一组有限的可能转换,您可以在已经构建的委托集合中使用某种机制进行运行时查找,但是没有办法生成可以任意将一种类型的值转换为任何其他类型的代码。

我想明白了。我首先创建了一个具有预期签名的方法:

public TOutput HandleTask<TTaskInput, TOutput>(TTaskInput task)

此方法处理转换和异常处理。然后,我使用Delegate.CreateDelegate创建该方法的委托实例,然后将其传递到动态ContinueWith调用中。

奔跑起来很有魅力。