I'm trying to invoke the RegisterType method in the Unity container. RegisterType has a total of 16 overrides (some of those are parameters some are types).
I'm trying to perform the equivalent of:
Container.RegisterType<IMyDataProvider, MockData.MockProvider>("MockData", new ContainerControlledLifetimeManager())
Using GetMethod() was a total failure, so I ended up doing this ugly thing:
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() });
And this works beautifully, up until the Invoke which complains because I have no InjectionMember parameters (they're optional and I don't have any to give). So, according to the documentation, I have to use Type.InvokeMember() to call a method with optional parameters.
So I did this:
Binder binder = new BootstrapperBinder();
Container.GetType().InvokeMember("RegisterType",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.OptionalParamBinding | BindingFlags.InvokeMethod,
binder,
Container,
new object[] { "MockData", new ContainerControlledLifetimeManager() });
My BoostrapperBinder class does this:
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 });
}
Yes, it's ugly, but I just use it for this oen case, so it does the job.
Now, the problem is, it's still complaining about the lack of a third parameter. I can't pass null or Missing.Value either, or it croaks. I've tried with and without BindingFlags.OptionalParamBinding. I'm stumped.
(Edited to put the Container.RegisterType example in code)
My initial post mentioned that I had tried passing null as a 3rd parameter and that the app "croaked." Specifically, it was getting a null reference exception and I should have been more clear about that.
The solution was to pass "new InjectionMember[0]" instead of null, so the Invoke() should have looked like this:
Thanks to Jason for his help. His sample sent me down the path that eventually led to the answer.
Croaks how? You should be able to pass
null
for aparams
parameter (when you invoke a method likeM(params object[] objects)
viaM()
it will be the case thatobjects
is null within the method.Second, you can lookup the method more cleanly. I don't have a compiler at my fingertips, but try this:
Then invoke the method like so, passing
null
for theparams InjectionMember[]
parameter:Sorry if it doesn't compile. If it doesn't compile, this will get you very close to a correct solution.
Here is a self-contained example that works:
This prints:
on the console.
params
is not part of the signature of a method. It is a compiler trick to allow variable-length parameter lists.BindingFlags.OptionalParamBinding
is for binding optional parameters to their default values.