C# 如何使用反射调用通用异步方法
我如何等待此C# 如何使用反射调用通用异步方法,c#,reflection,async-await,C#,Reflection,Async Await,我如何等待此任务?如何将其强制转换为任务?根据您的示例,您知道编译时返回对象的类型->IFoo,因此可以使用普通强制转换(IFoo) 但若在运行时任务的类型不是任务,则将抛出异常 如果您需要具体类型的IBar,那么 var method = typeof(IFoo).GetMethod(nameof(IFoo.Get)); var generic = method.MakeGenericMethod(bar2.GetType()); dynamic task = generic.Invoke(f
任务
?如何将其强制转换为任务?根据您的示例,您知道编译时返回对象的类型->IFoo
,因此可以使用普通强制转换(IFoo)
但若在运行时任务的类型不是任务
,则将抛出异常
如果您需要具体类型的IBar
,那么
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;
由于Task
源于Task
,因此您可以等待,一旦等待任务,您就可以使用反射通过反射安全地访问.Result
属性
获得结果后,您需要将其存储在IBar
中,并使用其上的方法和属性,或者在测试后转换到特定类型以使用特定类型的方法
这里有一个完整的MCVE
var concreteResult = Convert.ChangeType(result, bar2.GetType());
更新2:这里有一个新的扩展方法,通过使用dynamic
和GetAwaiter()
公共静态类扩展方法
{
公共静态异步任务InvokeAsync(this MethodInfo@this,object obj,params object[]参数)
{
dynamic awaitable=@this.Invoke(obj,参数);
等待着等待着;
返回awaitable.GetAwaiter().GetResult();
}
}
您可以使用“result”属性来避免使用“wait”关键字,并且不应在方法中标记为“async”
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();
}
}
var method=typeof(IFoo.GetMethod)(nameof(IFoo.Get));
var generic=method.MakeGenericMethod(typeof(IBar));
var task=(task)generic.Invoke(foo,new[]{bar2});
var resultProperty=task.GetProperty(“结果”);
var result=resultProperty.GetValue(任务);
var convertedResult=Convert.ChangeType(结果,bar2.GetType());
在@ScottChamberlain之上(这很好,答案是强制转换它,因为它返回一个对象(请参见@Fabio)。但是,你应该确保Foo
确实继承IFoo
,否则你会得到一个异常,因为Foo
(在调用中提供)类型错误。var task=(task)generic.Invoke(foo,new[]{bar2});
throwsInvalidCastException
无法将类型为'System.Threading.Tasks.task'
的对象强制转换为类型'System.Threading.Tasks.task'
动态任务=generic.Invoke(foo,new[]{bar2});IBar result=wait task;
始终返回null
@user2321864,而不是执行method.MakeGenericMethod(bar2.GetType());
您需要执行method.MakeGenericMethod(typeof(IBar))
那么第一个例子就可以了。任务
不是协变的,所以你不能将任务
强制转换为任务
@user2321864,动态任务…
与获取
方法返回的内容无关。我认为你需要检查获取
方法的行为。编译器错误CS0656:Der vom编译器angeforderte成员“Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create”fehlt。这指向上一个示例中“return”之后的可等待项。@ygoe将包Microsoft.CSharp添加到项目中请注意.GetAwaiter().GetResult()
阻止执行控件本身。@Rzassar No它不会,因为我们执行了wait waitable;
返回waitable.getwaitable().GetResult();
我们保证任务处于完成状态,因此GetResult()
将是一个非阻塞调用,因为结果将可用。
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;
var concreteResult = Convert.ChangeType(result, bar2.GetType());
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;
}
}
}
}
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);
}
}
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});
}
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();
}
}
var method = typeof(IFoo).GetMethod(nameof(IFoo.Get));
var generic = method.MakeGenericMethod(typeof(IBar));
var task = (Task<IBar>)generic.Invoke(foo, new [] { bar2 });
var resultProperty = task.GetProperty("Result");
var result = resultProperty.GetValue(task);
var convertedResult = Convert.ChangeType(result, bar2.GetType());