如何使用反射调用通用异步方法
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 {
...
}
}
然后我可以使用反射调用此方法:
I can then call this method using reflection:
var method = typeof(IFoo).GetMethod(nameof(IFoo.Get));
var generic = method.MakeGenericMethod(bar2.GetType());
var task = generic.Invoke(foo, new [] { bar2 });
如何等待此Task
?以及如何将其投射到Task<bar2.GetType()>
?
How do I await on this Task
? and How do I cast it to Task<bar2.GetType()>
?
由于Task<T>
是从Task
派生的,因此您可以等待,一旦等待任务,您就可以使用反射来安全地访问.Result
属性通过反射.
Because Task<T>
derives from Task
you can await on just that, once the task is awaited you can use reflection to safely access the .Result
property via reflection.
一旦获得结果,您将需要将其存储在IBar
中并使用其上的方法和属性,或者在进行测试以使用特定于类型的方法后强制转换为特定类型.
Once you have the result you will either need to store it in a IBar
and use the methods and properties on that or cast to the specific type after testing to use the type specific methods.
这是它的完整MCVE
Here is a full MCVE of it
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;
}
}
}
}
更新:这是一种简化过程的扩展方法
UPDATE: Here is a extension method to simplify the process
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);
}
}
这会将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});
}
更新2 :这是一种新的扩展方法,可通过dynamic
和GetAwaiter()
UPDATE 2: Here is a new extension method that works with any awaitable type instead of only tasks by using dynamic
and 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();
}
}