如何解决通过反射使用泛型和重写调用方法
| 我正在尝试在Unity容器中调用RegisterType方法。 RegisterType总共有16个覆盖(其中一些是参数,有些是类型)。 我正在尝试执行以下操作:Container.RegisterType<IMyDataProvider,MockData.MockProvider>(\"MockData\",new ContainerControlledLifetimeManager())
使用GetMethod()完全失败,所以我最终做了这件丑陋的事情:
MethodInfo registerTypeGeneric = Container.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).
Where(p => p.ToString() == \"Microsoft.Practices.Unity.IUnityContainer RegisterType[TFrom,TTo](System.String,Microsoft.Practices.Unity.LifetimeManager,Microsoft.Practices.Unity.InjectionMember[])\").FirstOrDefault();
MethodInfo registerTypeSpecific = registerTypeGeneric.MakeGenericMethod( new Type[] { typeof(IMyDataProvider),Assembly.LoadFrom(\"MockData.dll\").GetType(\"MockData.MockProvider\") });
registerTypeSpecific.Invoke(Container,new object[] { \"MockData\",new ContainerControlledLifetimeManager() });
直到收到Invoke投诉为止,因为我没有InjectionMember参数(它们是可选的,我没有提供任何参数),因此效果很好。因此,根据文档,我必须使用Type.InvokeMember()来调用带有可选参数的方法。
所以我这样做:
Binder binder = new BootstrapperBinder();
Container.GetType().InvokeMember(\"RegisterType\",BindingFlags.Instance | BindingFlags.Public | BindingFlags.OptionalParamBinding | BindingFlags.InvokeMethod,binder,Container,new ContainerControlledLifetimeManager() });
我的BoostrapperBinder类执行以下操作:
public override MethodBase BindToMethod(BindingFlags bindingAttr,MethodBase[] match,ref object[] args,ParameterModifier[] modifiers,System.Globalization.CultureInfo culture,string[] names,out object state)
{
Type mockProvider = Assembly.LoadFrom(\"MockData.dll\").GetType(\"MockData.MockProvider\");
state = new object();
MethodInfo mi = Container.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).
Where(p => p.ToString() == \"Microsoft.Practices.Unity.IUnityContainer RegisterType[TFrom,Microsoft.Practices.Unity.InjectionMember[])\").FirstOrDefault();
return mi.MakeGenericMethod(new Type[] { typeof(ICarrierApprovalDataChangeAccessorEndPoint),mockProvider });
}
是的,它很丑陋,但我只在这种情况下使用它,所以它可以完成工作。
现在的问题是,它仍在抱怨缺少第三个参数。我不能传递null或Missing.Value,否则它会崩溃。我尝试了有无BindingFlags.OptionalParamBinding。我很沮丧。
(已编辑以将Container.RegisterType示例放入代码中)
解决方法
我不能通过
null
或Missing.Value
,否则它会发出嘶哑的声音。
吱吱声如何?您应该能够为params
参数传递null
(当您通过M()
调用类似M(params object[] objects)
的方法时,方法中objects
为null的情况。
其次,您可以更清晰地查找该方法。我没有指尖的编译器,但是请尝试以下操作:
var registerTypeMethodInfo =
typeof(IUnityContainer).GetMethods()
.Where(m => m.Name == \"RegisterType\")
.Where(m => m.GetParameters()
.Select(p => p.ParameterType)
.SequenceEqual(new[] {
typeof(string),typeof(LifetimeManager),typeof(InjectionMember[])
})
)
.Where(m => m.GetGenericArguments().Count() == 2)
.SingleOrDefault();
Assert.NotNull(registerTypeMethodInfo);
var methodInfo =
registerTypeMethodInfo.MakeGenericMethod(new[] {
typeof(IMyDataProvider),typeof(MockData.MockProvider)
});
然后像这样调用方法,将null
传递给params InjectionMember[]
参数:
methodInfo.Invoke(
Container,new object[] {
\"MockData\",new ContainerControlledLifetimeManager(),null
}
);
对不起,如果没有编译。如果没有编译,这将使您非常接近正确的解决方案。
这是一个独立的示例,可以正常工作:
namespace ParamsTest {
interface Foo {
void M<T>(string s,int n,params object[] objects);
}
class Bar : Foo {
public void M<T>(string s,params object[] objects) {
Console.WriteLine(s);
Console.WriteLine(n);
Console.WriteLine(objects == null);
Console.WriteLine(typeof(T).Name);
}
}
internal class Program {
internal static void Main(string[] args) {
var genericMethodInfo =
typeof(Foo).GetMethods()
.Where(m => m.Name == \"M\")
.Where(m => m.GetParameters()
.Select(p => p.ParameterType)
.SequenceEqual(new[] {
typeof(string),typeof(int),typeof(object[])
})
)
.Where(m => m.GetGenericArguments().Count() == 1)
.SingleOrDefault();
var methodInfo =
genericMethodInfo.MakeGenericMethod(
new[] { typeof(DateTime) }
);
var bar = new Bar();
methodInfo.Invoke(bar,new object[] { \"Hello,world!\",17,null });
}
}
}
打印:
Hello,world!
17
True
DateTime
在控制台上。
我尝试了有无BindingFlags.OptionalParamBinding。我很沮丧。
params
不是方法签名的一部分。这是允许可变长度参数列表的编译器技巧。 BindingFlags.OptionalParamBinding
用于将可选参数绑定到其默认值。
, 我的第一篇文章提到我曾尝试将null作为第三个参数传递,并且应用程序“崩溃了”。具体地说,它收到了null引用异常,对此我应该更加清楚。
解决方案是传递\“ new InjectionMember [0] \”而不是null,因此Invoke()应该看起来像这样:
registerTypeSpecific.Invoke(Container,new object[] { \"MockData\",new InjectionMember[0] });
感谢Jason的帮助。他的样本将我带到了最终导致答案的道路上。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。