转换任务<;对象>;到任务<;T>;其中T是未知的

本文关键字:gt lt 任务 未知 其中 对象 转换 | 更新日期: 2023-09-27 18:28:45

在T未知的情况下,如何将Task<object>转换为Task<T>

例如Task<object> to Task<int>

interface IAsyncActions
{
    Task<int> GetValueAsync();
}
class Proxy : RealProxy
{
    public Proxy() : base(typeof(IAsyncActions)) { }
    public override IMessage Invoke(IMessage msg)
    {
        var call = (IMethodCallMessage)msg;
        var method = (MethodInfo)call.MethodBase;
        if (method.ReturnType.IsSubclassOf(typeof(Task)))
        {
            // return type is Task<T>
            Task taskResult = AsyncMethod2(call);
            return new ReturnMessage(taskResult, null, 0, call.LogicalCallContext, call); // InvalidCastException if taskResult not a Task<int>
        }
        else
        {
            // ...
            return null;
        }
    }
    static void Main()
    {
        Proxy p = new Proxy();
        IAsyncActions tProxy = (IAsyncActions)p.GetTransparentProxy();
        int result = tProxy.GetValueAsync().Result; // InvalidCastException
    }
    // This method works fine
    Task AsyncMethod(IMethodCallMessage call)
    {
        Task<int> task = Task.FromResult(1234);
        return task;
    }
    // This method does not work
    Task AsyncMethod2(IMethodCallMessage call)
    {
        Type taskReturnType = ((MethodInfo)call.MethodBase).ReturnType; // Task<int>
        Task<object> result = Task.FromResult<object>(1234);
        // converting result to taskReturnType
        // ...
        //
        return result;
    }
}

我找到了一个解决方案,但它相当昂贵:

Task AsyncMethod2(IMethodCallMessage call, MethodInfo method)
{
    PropertyInfo resultProp = method.ReturnType.GetProperty("Result");
    Type taskResultType = resultProp.PropertyType;
    Type tcs = typeof(TaskCompletionSource<>);
    Type[] typeArgs = { taskResultType };
    Type genericTcs = tcs.MakeGenericType(typeArgs);
    var taskProperty = genericTcs.GetProperty("Task");
    object tcsInstance = Activator.CreateInstance(genericTcs);
    MethodInfo setResult = genericTcs.GetMethod("SetResult");
    MethodInfo setException = genericTcs.GetMethod("SetException", new Type[] { typeof(IEnumerable<Exception>)});
    var setEx = (Action< IEnumerable<Exception>>)setException.CreateDelegate(typeof(Action<IEnumerable<Exception>>), tcsInstance);
    Task task = (Task)taskProperty.GetValue(tcsInstance);
    Task<object> result = new Task<object>(delegate 
    {
        //throw new InvalidOperationException("qwerty");
        return 1234;
    });
    result.Start();
    result.ContinueWith(x =>
    {
        var args = new object[] { x.Result };
        setResult.Invoke(tcsInstance, args);
    }, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion);
    result.ContinueWith(x =>
    {
        setEx(x.Exception.InnerExceptions);
    }, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnFaulted);
    return task;
}

转换任务<;对象>;到任务<;T>;其中T是未知的

创建此方法:

public async static Task<T> Convert<T>(Task<object> task)
{
    var result = await task;
    return (T) result;
}

然后你可以做这样的事情(这是必要的,因为T只在运行时才知道):

//Assuming that variable "task" is referencing the Task<object>
Type taskReturnType = ((MethodInfo) call.MethodBase).ReturnType; //e.g. Task<int>
var type = taskReturnType.GetGenericArguments()[0]; //get the result type, e.g. int
var convert_method = this.GetType().GetMethod("Convert").MakeGenericMethod(type); //Get the closed version of the Convert method, e.g. Convert<int>
var result = convert_method.Invoke(null, new object[] {task}); //Call the convert method and return the generic Task, e.g. Task<int>