在任务中将TResult转换为System.Object

我正在加载一个程序集并调用一个静态方法,该方法将使用MethodInfo.Invoke()通过reflection创建一个类型为“MyClass1”的新对象(此类型在运行时指定)。 当方法是普通同步方法时,这可以正常工作。 但是,被调用的方法是一个异步方法,它返回Task ,它将用于使用task.Result检索结果。

理想情况下,我应该在任务中使用MyClass1作为TResult,但类型仅在运行时确定,所以我不能这样做。 我正在寻找一种方法来获得任务和结果。 我试图将TResult转换为System.Object并将该类作为通用对象。 以下是我为此目的使用的代码。

public static void LoadAssembly() { // Calling static async method directly works fine Task 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 task = (Task)mi.Invoke(obj, null); // Exception occurs here. Object result = task.Result; } 

以下是通过reflection调用的方法(测试代码)。 这个

 public class MyClass1 { public static async Task MakeMyClass1() { MyClass1 newObject = null; await Task.Run(() => { newObject = new MyClass1(); }); return newObject; } ... } 

不幸的是,TResult的转换导致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]'. 

如何将Task 中的TResult转换为通用对象并使用task.Result获取结果? 我将不胜感激任何帮助解决这个问题。

你不能将Task TaskTask ,因为Task不是协变的 (它也不是逆变的)。 最简单的解决方案是使用更多reflection:

 var task = (Task) mi.Invoke (obj, null) ; var result = task.GetType ().GetProperty ("Result").GetValue (task) ; 

这是缓慢且低效的,但如果不经常执行此代码,则可以使用。 另外,如果您要阻止等待其结果,那么使用异步MakeMyClass1方法有什么用?

另一种可能性是为此目的编写扩展方法:

  public static Task Convert(this Task task) { TaskCompletionSource res = new TaskCompletionSource(); return task.ContinueWith(t => { if (t.IsCanceled) { res.TrySetCanceled(); } else if (t.IsFaulted) { res.TrySetException(t.Exception); } else { res.TrySetResult(t.Result); } return res.Task; } , TaskContinuationOptions.ExecuteSynchronously).Unwrap(); } 

它是无阻塞解决方案,将保留Task的原始状态/exception。

作为对已接受答案的增强,您可以通过在两者之间等待Task来避免阻塞:

 var task = (Task)mi.Invoke(obj, null); await task; var result = task.GetType().GetProperty("Result").GetValue(task); 

当然,只有当调用堆栈中的所有方法都标记为async并且您在任何地方使用await而不是.Result这将是正确的异步。