use*_*864 20 c# reflection async-await
public interface IBar {
}
public class Bar : IBar {
}
public class Bar2 : IBar {
}
public interface IFoo {
Task<T> Get<T>(T o) where T : IBar;
}
public class Foo : IFoo {
public async Task<T> Get<T>(T o) where T : IBar {
...
}
}
Run Code Online (Sandbox Code Playgroud)
然后我可以使用反射调用此方法:
var method = typeof(IFoo).GetMethod(nameof(IFoo.Get));
var generic = method.MakeGenericMethod(bar2.GetType());
var task = generic.Invoke(foo, new [] { bar2 });
Run Code Online (Sandbox Code Playgroud)
我该如何等待Task?以及如何将其投射到Task<bar2.GetType()>?
Sco*_*ain 35
由于Task<T>派生自Task你可以只是等待,一旦任务等待你可以使用反射来安全地访问.Result通过反射特性.
获得结果后,您需要将其存储在a中IBar并使用其上的方法和属性,或者在测试后转换为特定类型以使用特定于类型的方法.
这是一个完整的MCVE
using System;
using System.Reflection;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Test().Wait();
Console.ReadLine();
}
static async Task Test()
{
var foo = new Foo();
var bar2 = new Bar2();
object resultObject = await CallGetByReflection(foo, bar2);
IBar result = (IBar)resultObject;
result.WriteOut();
//or
if (resultObject is Bar)
{
((Bar)resultObject).Something();
}
else if (resultObject is Bar2)
{
((Bar2)resultObject).SomethingElse();
}
}
private static async Task<object> CallGetByReflection(IFoo foo, IBar bar)
{
var method = typeof(IFoo).GetMethod(nameof(IFoo.Get));
var generic = method.MakeGenericMethod(bar.GetType());
var task = (Task) generic.Invoke(foo, new[] {bar});
await task.ConfigureAwait(false);
var resultProperty = task.GetType().GetProperty("Result");
return resultProperty.GetValue(task);
}
public interface IBar
{
void WriteOut();
}
public class Bar : IBar
{
public void Something()
{
Console.WriteLine("Something");
}
public void WriteOut()
{
Console.WriteLine(nameof(Bar));
}
}
public class Bar2 : IBar
{
public void SomethingElse()
{
Console.WriteLine("SomethingElse");
}
public void WriteOut()
{
Console.WriteLine(nameof(Bar2));
}
}
public interface IFoo
{
Task<T> Get<T>(T o) where T : IBar;
}
public class Foo : IFoo
{
public async Task<T> Get<T>(T o) where T : IBar
{
await Task.Delay(100);
return o;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新:这是一个简化过程的扩展方法
public static class ExtensionMethods
{
public static async Task<object> InvokeAsync(this MethodInfo @this, object obj, params object[] parameters)
{
var task = (Task)@this.Invoke(obj, parameters);
await task.ConfigureAwait(false);
var resultProperty = task.GetType().GetProperty("Result");
return resultProperty.GetValue(task);
}
}
Run Code Online (Sandbox Code Playgroud)
这将打开CallGetByReflection到
private static Task<object> CallGetByReflection(IFoo foo, IBar bar)
{
var method = typeof(IFoo).GetMethod(nameof(IFoo.Get));
var generic = method.MakeGenericMethod(bar.GetType());
return generic.InvokeAsync(foo, new[] {bar});
}
Run Code Online (Sandbox Code Playgroud)
更新2:这是一个新的扩展方法,可以使用dynamic和使用任何等待类型而不是任务GetAwaiter()
public static class ExtensionMethods
{
public static async Task<object> InvokeAsync(this MethodInfo @this, object obj, params object[] parameters)
{
dynamic awaitable = @this.Invoke(obj, parameters);
await awaitable;
return awaitable.GetAwaiter().GetResult();
}
}
Run Code Online (Sandbox Code Playgroud)
除了@ScottChamberlain 的回答(这很棒)之外,我建议对InvokeAsyncreturnTask<T>而不是Task<object>. 除此之外,有第二种方法返回 会很有用Task,但InvokeAsync.
using System.Threading.Tasks;
namespace System.Reflection
{
public static class MethodInfoExtensions
{
public static async Task<T> InvokeAsync<T>(this MethodInfo methodInfo, object obj, params object[] parameters)
{
dynamic awaitable = methodInfo.Invoke(obj, parameters);
await awaitable;
return (T)awaitable.GetAwaiter().GetResult();
}
public static async Task InvokeAsync(this MethodInfo methodInfo, object obj, params object[] parameters)
{
dynamic awaitable = methodInfo.Invoke(obj, parameters);
await awaitable;
}
}
}
Run Code Online (Sandbox Code Playgroud)
根据您的示例,您知道在编译时返回的对象的类型-> IFoo,因此可以使用常规转换(IFoo)
var method = typeof(IFoo).GetMethod(nameof(IFoo.Get));
var generic = method.MakeGenericMethod(typeof(IBar));
var task = (Task<IBar>)generic.Invoke(foo, new [] { bar2 });
IBar result = await task;
Run Code Online (Sandbox Code Playgroud)
如果您在编译时不知道类型,则只需使用dynamic关键字
var method = typeof(IFoo).GetMethod(nameof(IFoo.Get));
var generic = method.MakeGenericMethod(bar2.GetType());
dynamic task = generic.Invoke(foo, new [] { bar2 });
IBar result = await task;
Run Code Online (Sandbox Code Playgroud)
但是,如果任务的类型不是Task<iFoo>在运行时-将会抛出异常
。如果您需要具体的类型,IBar则
var concreteResult = Convert.ChangeType(result, bar2.GetType());
Run Code Online (Sandbox Code Playgroud)