mtc*_*cup 9 c# asynchronous task
我正在加载一个程序集并调用一个静态方法,该方法将使用MethodInfo.Invoke()通过反射创建一个类型为"MyClass1"的新对象(此类型在运行时指定).当方法是普通同步方法时,这可以正常工作.但是,被调用的方法是一个异步方法,它返回Task <MyClass1>,它将用于使用task.Result检索结果.
理想情况下,我应该在任务中使用MyClass1作为TResult,但类型仅在运行时确定,所以我不能这样做.我正在寻找一种方法来获得任务和结果.我试图将TResult转换为System.Object并将该类作为通用对象.以下是我为此目的使用的代码.
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;
}
Run Code Online (Sandbox Code Playgroud)
以下是通过反射调用的方法(测试代码).这个
public class MyClass1
{
public static async Task<MyClass1> MakeMyClass1()
{
MyClass1 newObject = null;
await Task.Run(() =>
{
newObject = new MyClass1();
});
return newObject;
}
...
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,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]'.
Run Code Online (Sandbox Code Playgroud)
如何将Task <>中的TResult转换为通用对象并使用task.Result获取结果?我将不胜感激任何帮助解决这个问题.
Ant*_*hyy 18
你可以不投Task<T>给Task<object>,因为Task<T>不是协变(这不是逆变,要么).最简单的解决方案是使用更多反射:
var task = (Task) mi.Invoke (obj, null) ;
var result = task.GetType ().GetProperty ("Result").GetValue (task) ;
Run Code Online (Sandbox Code Playgroud)
这是缓慢且低效的,但如果不经常执行此代码则可以使用.顺便说一句,MakeMyClass1如果要阻止等待其结果,有什么用异步方法?
小智 8
另一种可能性是为此目的编写扩展方法:
public static Task<object> Convert<T>(this Task<T> task)
{
TaskCompletionSource<object> res = new TaskCompletionSource<object>();
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();
}
Run Code Online (Sandbox Code Playgroud)
它是无阻塞解决方案,将保留Task的原始状态/异常.
作为对已接受答案的增强,您可以通过等待Task中间来避免阻塞:
var task = (Task)mi.Invoke(obj, null);
await task;
var result = task.GetType().GetProperty("Result").GetValue(task);
Run Code Online (Sandbox Code Playgroud)
当然,只有当调用堆栈中的所有方法都被标记async并且您正在使用await而不是在.Result任何地方时,这才是正确的异步.
| 归档时间: |
|
| 查看次数: |
8649 次 |
| 最近记录: |