How can i convert Task<object>
to Task<T>
where T is unknown?
For example
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;
}
}
I found one solution but it is quite expensive:
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;
}
Create this method:
public async static Task<T> Convert<T>(Task<object> task)
{
var result = await task;
return (T) result;
}
And then you can do something like this (this is needed because T is only known at runtime):
//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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With