I am loading an assembly and calling a static method that will create a new object of type “MyClass1” (this type is specified at runtime) through reflection using MethodInfo.Invoke(). This works fine when the method is a normal sync method. However, the method being called is an async method which returns Task<MyClass1>, which will be used to retrieve the result using task.Result.
Ideally I should be using MyClass1 as TResult in the task, but the type is determined only at runtime so I can't do that. I am looking for a way to get the task and the result. I am trying to cast the TResult to System.Object and get the class as a generic Object. The following is the code I am using for this purpose.
public static void LoadAssembly()
{
// Calling static async method directly works fine
Task<MyClass1> task1 = MyClass1.MakeMyClass1();
MyClass1 myClass1 = task1.Result;
// Calling static async method through reflection through exception.
Assembly assembly = Assembly.LoadFrom(dllName);
Type type = assembly.GetType("AsyncDll.MyClass1");
var types = assembly.GetTypes();
MethodInfo[] methodInfos = types[0].GetMethods(BindingFlags.Public | BindingFlags.Static);
Type myClassType = types[0];
MethodInfo mi = myClassType.GetMethod("MakeMyClass1");
Object obj = Activator.CreateInstance(mi.ReflectedType);
Task<Object> task = (Task<Object>)mi.Invoke(obj, null); // Exception occurs here.
Object result = task.Result;
}
Following is the method (test code) being called through reflection. This
public class MyClass1
{
public static async Task<MyClass1> MakeMyClass1()
{
MyClass1 newObject = null;
await Task.Run(() =>
{
newObject = new MyClass1();
});
return newObject;
}
...
}
Unfortunately, the casting of TResult is causing System.InvalidCastException.
An unhandled exception of type 'System.InvalidCastException' occurred in Test.exe
Additional information: Unable to cast object of type 'System.Threading.Tasks.Task`1[MyClass1]' to type 'System.Threading.Tasks.Task`1[System.Object]'.
How can I cast the TResult in Task<> to a generic object and get the result using task.Result? I would appreciate any help resolving this issue.
You cannot cast
Task<T>
toTask<object>
, becauseTask<T>
is not covariant (it's not contravariant, either). The simplest solution would be to use some more reflection:This is slow and inefficient, but usable if this code is not executed often. As an aside, what is the use of having an asynchronous
MakeMyClass1
method if you are going to block waiting for its result?Another possibility is to write an extension method to this purpose:
It is none-blocking solution and will preserve original state/exception of the Task.
As an enhancement to the accepted answer, you can avoid the blocking by awaiting the
Task
in between:Of course this will be properly asynchronous only if all methods up the call stack are marked
async
and you're usingawait
instead of.Result
everywhere.