- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试调用 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() });
这工作得很好,直到调用提示,因为我没有 InjectionMember 参数(它们是可选的,我没有任何参数)。因此,根据文档,我必须使用 Type.InvokeMember() 来调用带有可选参数的方法。
所以我这样做了:
Binder binder = new BootstrapperBinder();
Container.GetType().InvokeMember("RegisterType",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.OptionalParamBinding | BindingFlags.InvokeMethod,
binder,
Container,
new object[] { "MockData", 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,TTo](System.String, Microsoft.Practices.Unity.LifetimeManager, Microsoft.Practices.Unity.InjectionMember[])").FirstOrDefault();
return mi.MakeGenericMethod(new Type[] { typeof(ICarrierApprovalDataChangeAccessorEndPoint), mockProvider });
}
是的,它很丑,但我只是将它用于这种情况,所以它可以完成工作。
现在,问题是,它仍在提示缺少第三个参数。我也不能传递 null 或 Missing.Value,否则它会发出声音。我试过使用和不使用 BindingFlags.OptionalParamBinding。我很难过。
(编辑以将 Container.RegisterType 示例放入代码中)
最佳答案
I can't pass
null
orMissing.Value
either, or it croaks.
怎么叫?您应该能够为 params
参数传递 null
(当您调用类似 M(params object[] objects) 的方法时
通过 M()
在方法中 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)
});
然后像这样调用方法,为 params InjectionMember[]
参数传递 null
:
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, int n, 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
在控制台上。
I've tried with and without BindingFlags.OptionalParamBinding. I'm stumped.
params
不是方法签名的一部分。允许可变长度参数列表是一种编译器技巧。 BindingFlags.OptionalParamBinding
用于将可选参数绑定(bind)到它们的默认值。
关于c# - 使用泛型和覆盖通过反射调用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6333896/
我是一名优秀的程序员,十分优秀!