使用反射调用方法
Use reflection to invoke method
在使用 Azure ServiceFabric 时,我们使用 StateManager.GetStateAsync
方法获取值,可以使用相同的方法获取对象类型的值,如 类.
我正在尝试使用以下代码
var typeObj = Activator.CreateInstance(type);
var method = typeof(IActorStateManager).GetMethod(nameof(IActorStateManager.GetStateAsync));
var generic = method.MakeGenericMethod(type);
dynamic task = generic.Invoke(typeObj, new[] { stateName })
object result = await task;
通过这种方法,我遇到了异常。
Data: {System.Collections.ListDictionaryInternal}
HResult: -2146232829
HelpLink: null
InnerException: null
Message: "Object does not match target type."
Source: "mscorlib"
StackTrace: "at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)"
TargetSite: {Void CheckConsistency(System.Object)}
这里很可能混淆了一些事情。如果您的代码就是您实际执行的代码,那么您就是 over/misusing type
变量。
让我们决定type
是一个具体的ActorStateManager
。然后
var typeObj = Activator.CreateInstance(type); // typeobj is now ActorStateManager
错误大概在这里:
var generic = method.MakeGenericMethod(type);
// generic is now StateManager.GetStateAsync<ActorStateManager>
您的意图不是创建 StateManager.GetStateAsync<ActorStateManager>
,而是
StateManager.GetStateAsync<bool>
或 StateManager.GetStateAsync<DateTime>
。
此外,我将 GetStateAsync takes an (optional?) cancellationToken 作为第二个参数,在进行反射时最好明确。
所以我猜这就是你想要做的:
public async Task<object> TryLotsOfTypesAndIgnoreErrors(string stateName)
{
var typeObj = Activator.CreateInstance(typeof(ActorStateManager));
foreach (var typeParam in new[] {typeof(bool), typeof(string)})
{
try
{
var method = typeof(IActorStateManager).GetMethod(nameof(IActorStateManager.GetStateAsync));
var generic = method.MakeGenericMethod(typeParam);
var task = (Task) generic.Invoke(typeObj, new object[] { stateName, CancellationToken.None });
await task;
return task.GetType().GetProperty(nameof(Task<object>.Result))?.GetValue(task);
}
catch
{
// TODO: Catch only exception specific to type mismatch
}
}
return null;
}
在使用 Azure ServiceFabric 时,我们使用 StateManager.GetStateAsync
方法获取值,可以使用相同的方法获取对象类型的值,如 类.
我正在尝试使用以下代码
var typeObj = Activator.CreateInstance(type);
var method = typeof(IActorStateManager).GetMethod(nameof(IActorStateManager.GetStateAsync));
var generic = method.MakeGenericMethod(type);
dynamic task = generic.Invoke(typeObj, new[] { stateName })
object result = await task;
通过这种方法,我遇到了异常。
Data: {System.Collections.ListDictionaryInternal}
HResult: -2146232829
HelpLink: null
InnerException: null
Message: "Object does not match target type."
Source: "mscorlib"
StackTrace: "at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)"
TargetSite: {Void CheckConsistency(System.Object)}
这里很可能混淆了一些事情。如果您的代码就是您实际执行的代码,那么您就是 over/misusing type
变量。
让我们决定type
是一个具体的ActorStateManager
。然后
var typeObj = Activator.CreateInstance(type); // typeobj is now ActorStateManager
错误大概在这里:
var generic = method.MakeGenericMethod(type);
// generic is now StateManager.GetStateAsync<ActorStateManager>
您的意图不是创建 StateManager.GetStateAsync<ActorStateManager>
,而是
StateManager.GetStateAsync<bool>
或 StateManager.GetStateAsync<DateTime>
。
此外,我将 GetStateAsync takes an (optional?) cancellationToken 作为第二个参数,在进行反射时最好明确。
所以我猜这就是你想要做的:
public async Task<object> TryLotsOfTypesAndIgnoreErrors(string stateName)
{
var typeObj = Activator.CreateInstance(typeof(ActorStateManager));
foreach (var typeParam in new[] {typeof(bool), typeof(string)})
{
try
{
var method = typeof(IActorStateManager).GetMethod(nameof(IActorStateManager.GetStateAsync));
var generic = method.MakeGenericMethod(typeParam);
var task = (Task) generic.Invoke(typeObj, new object[] { stateName, CancellationToken.None });
await task;
return task.GetType().GetProperty(nameof(Task<object>.Result))?.GetValue(task);
}
catch
{
// TODO: Catch only exception specific to type mismatch
}
}
return null;
}