等待任务<服务的结果>在非泛型方法中使用反射
本文关键字:泛型方法 反射 任务 服务 结果 等待 | 更新日期: 2023-09-27 18:30:42
考虑以下情况:
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
',但也许我在这里错过了一个边缘情况。除此之外,我该如何完成这项工作?谢谢!
根据我的评论:
与接口不同,具体类型(如
Task<TResult>
)不能是协变的。请参阅为什么任务不是协变?。所以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;
我需要在城堡拦截器中获取任务结果。这段代码对我有用:
if (invocation.ReturnValue is Task task)
{
task.Wait();
var result = invocation.ReturnValue.GetType().GetProperty("Result").GetValue(task);
_cacheProvider.Set(_key, result, _duration);
}
我的选项具有扩展方法的形式。它接受任何Task
实例,并返回具有一般任务的实际结果或非通用任务的实际结果null
Task<object?>
。
internal static class TaskExtensions
{
public static async Task<object?> ToGenericTaskAsync(this Task task)
{
await task;
var taskType = task.GetType();
if (!taskType.IsGenericType
|| taskType.GetGenericTypeDefinition() != typeof(Task<>)
|| taskType.GetGenericArguments()[0] == Type.GetType("System.Threading.Tasks.VoidTaskResult"))
{
return null;
}
return task
.GetType()
.GetProperty(nameof(Task<object>.Result), BindingFlags.Instance | BindingFlags.Public)!
.GetValue(task);
}
}
用法:
Task<object?> t1 = await Task.CompletedTask.ToGenericTaskAsync();
Task<object?> t2 = await Task.FromResult<int>(5).ToGenericTaskAsync();
.NET 小提琴中的示例
上面的解决方案确实对我有帮助。 我对@Lukazoid解决方案进行了小调整...
var resultProperty = typeof(Task<>).MakeGenericType(type).GetProperty("Result");
A a = (A)resultProperty.GetValue(task);
自
dynamic a = task.GetType().GetProperty("Result")?.GetValue(task);