考虑以下情况:
class A
{
public int Id;
}
class B : A
{
}
class Main
{
public async Task<int> Create(Type type)
{
MethodInfo method = this.GetType().GetMethod("Create", new Type[] { typeof(string) }).MakeGenericMethod(new Type[] { type });
A a = await (Task<A>)method.Invoke(this, new object[] { "humpf" });
return a.Id;
}
public async Task<T> Create<T>(string name) where T : A
{
T t = await Foo.Bar<T>(name);
return t;
}
}
调用new Main().Create(typeof(B))
将失败并显示
无法将“
System.Threading.Tasks.Task[B]
”类型的对象转换为 输入“System.Threading.Tasks.Task[A]
”
我不太明白,因为在这种情况下,通用Create<T>
方法只能返回Task<T>
,其中T
始终来自“A
”,但也许我在这里错过了一个边缘案例。
除此之外,我怎样才能做到这一点?谢谢!
答案 0 :(得分:20)
根据我的评论:
与接口不同,
Task<TResult>
等具体类型不能协变。见Why is Task not co-variant?。因此,无法将Task<B>
分配给Task<A>
。
我能想到的最佳解决方案是使用基础类型Task
来执行await
,如下所示:
var task = (Task)method.Invoke(this, new object[] { "humpf" });
await task;
然后您可以使用反射来获取Result
:
var resultProperty = typeof(Task<>).MakeGenericType(type).GetProperty("Result");
A a = (A)resultProperty.GetValue(task);
return a.Id;
答案 1 :(得分:0)
我需要在 Castle Interceptor 中获取任务结果。此代码适用于我:
if (invocation.ReturnValue is Task task)
{
task.Wait();
var result = invocation.ReturnValue.GetType().GetProperty("Result").GetValue(task);
_cacheProvider.Set(_key, result, _duration);
}
答案 2 :(得分:-1)
上述解决方案确实对我有所帮助。我对@Lukazoid解决方案做了一个小调整...
var resultProperty = typeof(Task<>).MakeGenericType(type).GetProperty("Result");
A a = (A)resultProperty.GetValue(task);
到
dynamic a = task.GetType().GetProperty("Result")?.GetValue(task);