views:

41

answers:

3

Hi,

I'm using Microsoft Unity. I have an interface ICustomerService and its implementation CustomerService. I can register them for the Unity container using the following code:

container.RegisterType<ICustomerService, CustomerService>(new TransientLifetimeManager());

If CustomerService has a certain parameter in its constructor (e.g. ISomeService1), I use the following code (I need to specify SomeService1):

container.RegisterType<ICustomerService, CustomerService>(new TransientLifetimeManager(), new InjectionConstructor(new SomeService1()));

No problems here.

The problem appears when CustomerService class has two parameters (not one param as in the previous example) in its constructor (e.g. ISomeService1 and ISomeService2). It works fine when I'm using the following code: container.RegisterType(new TransientLifetimeManager(), new InjectionConstructor(new SomeService1(), new SomeService2()));

The problem is that I do not want specify SomeService2() for the second parameter. I want to specify only first parameter - SomeService1(). But I get the error that I need to specify none or both of parameters.

How can I specify only first parameter of constructor?

Thanks in advance

A: 

You can default the second parameter to the constructor (e.g., =null) or offer a single parameter constructor in addition to the two parameter constructor by overloading it.

Michael Goldshteyn
+1  A: 

Your best answer is to actually use the container.

What you're doing is saying "when building this type, use this specific instance of the object." This doesn't take advantage of the ability of the container to build up instance for you. Instead, you should register IService1 and IService2 in the container. Then, tell the container to resolve those dependencies for you.

It looks something like this:

container.RegisterType<IService1, SomeService1>();
container.RegisterType<IService2, SomeService2>();

What this does is tell the container "whenever there's a dependency of type IService1, new up a new object of type SomeService1 and hand it that" and similarly for IService2.

So next, you need to tell the container what to do about ICustomerService. In most generality, you'd do this:

container.RegisterType<ICustomerService, CustomerService>(
    // Note, don't need to explicitly say transient, that's the default
    new InjectionConstructor(new ResolvedParameter<IService1>(),
        new ResolvedParameter<IService2>()));

This tells the container: when resolving ICustomerService, new up an instance of CustomerService using the constructor that takes IService1 and IService2. To get those parameters, call back into the container to resolve those types.

This is a bit verbose, and a common case, so there are some shortcuts. First off, you can pass a Type object instead of doing new ResolvedParameter, like so:

container.RegisterType<ICustomerService, CustomerService>(
    new InjectionConstructor(typeof(IService1), typeof (IService2)));

As another shorthand, if CustomerService has only one constructor, or if the one you want called is the one that takes the largest parameter list, you can leave the InjectionConstructor out completely, as that's the constructor that the container will pick in the absence of other configuration.

container.RegisterType<ICustomerService, CustomerService>();

The form you're using is typically used when you want a specific value passed for a constructor parameter rather than resolving the service back through the container.

To answer your original question - well, you can't do exactly what you said. The constructor parameter needs A value of some sort. You could put anything else in there you want, though - null typically works.

Note you can also mix the two forms. For example, if you want to resolve IService1 and pass null for the IService2 parameter, do this:

container.RegisterType<ICustomerService, CustomerService>(
    new InjectionConstructor(typeof(IService1), null));

* EDIT *

Based on the comment below, what you actually want is another feature - named registrations.

Basically, you have two implementations of IService1 and one of IService2. So, what you can do is register both of them, and then tell the container which one to use.

First off, to register the second implementation, you need to give an explicit name:

container.RegisterType<IService1, OtherService1Impl>("other");

Then you can tell the container to resolve IService1 but use the name. This is the main reason that the ResolvedParameter type exists. Since you just want the default for IService2, you can use typeof() as a shorthand. You still need to specify both types for the parameters, but you don't need a specific value. If that makes any sense.

container.RegisterType<ICustomerService, CustomerService>(
    new InjectionConstructor(new ResolvedParameter<IService1>("other"), typeof(IService2));

That should do what you need.

Chris Tavares
Chris, thanks. But the problem is that I have two implementations of IService1. Let's name them Service1Impl1 and Service1Impl2. Both of them are used in the solution. CustomerManager should use Service1Impl1 and OrderManager should use Service1Impl2. That's why I need to specify Service1Impl1 as the first parameter of CustomerService. But I don't want to specify the second parameter because there's only one used implementation of IService2 and it's already registered using the following source code: container.RegisterType<IService2, SomeService2>();
user475681
I'll edit my answer, it'll require a little more detail than I can fit in a comment.
Chris Tavares
Great answer Chris.
OJ
A: 

As an alternative of Chris Tavares' answer, you can let the container resolve only the second parameter:

container.RegisterType<ICustomerService, CustomerService>(
    new InjectionConstructor(new SomeService1(), new ResolvedParameter<IService2>());
onof