13

I'm using Prism, which gives be the nice Unity IoC container too. I'm new to the concept, so I haven't gotten my hands all around it yet. What I want to do now is to create an object using the IoC container, but passing an extra parameter too. Allow me to explain with an example..:

I have a class that takes a commands object. This is registered in the IoC container, so it will handle it nicely:

public class Person 
{
    public Person(IApplicationCommands commands) { .. }
    ..
}

Person person = _container.Resolve<Person>();

Now - I want to pass in another argument - e.g. the name of the person. However, I still want to use the IoC container to handle the resolving and hence get the other paramenters from the IoC container. But pass in the name as a "custom" parameter. Can this be done?

public class Person 
{
    public Person(IApplicationCommands commands, string name) { .. }
    ..
}

string name = "John"; 
Person person = _container.Resolve<Person>(name); // ....?? 

This example doesn't seem to work, but is there a way to make it work? Or does Unity IoC container require all parameters to be registered in the container before calling Resolve?

stiank81
  • 25,418
  • 43
  • 131
  • 202

4 Answers4

18

Can I pass constructor parameters to Unity's Resolve() method?

container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"
Community
  • 1
  • 1
NotDan
  • 31,709
  • 36
  • 116
  • 156
9

Edit: this answer is obsolete, in my opinion, because it has an assumption of an older version of Unity. NotDan's answer is better.


You've got a few options. They are honestly a bit lame, but they will work.

Option 1: Scoped Container

If you want to use constructor injection, you'll need to create a scoped container and put your data into that scoped container:

IUnityContainer subContainer = _container.CreateChildContainer();

//Don't do this... create a custom type other than string, like
// MyConstructorParams or something like that... this gets the point across.
subContainer.RegisterInstance<string>("John");
Person person = subContainer.Resolve<Person>();

Option 2: Initialize Method

What I typically do, though, is have a seperate Initialize method on my target objects for instance variables:

public class Person
{
     public Person(IApplicationCommands commands)
     { .. }
     public void Initialize(string name) { .. }

     ..
}

And then your usage becomes:

Person person = container.Resolve<Person>();
person.Initialize("John");

Neither is particularly pleasant, but it'll get the job done. The important thing is to pick a convention and stick to it, otherwise you'll get a bit lost.

Hope this helps.

Community
  • 1
  • 1
Anderson Imes
  • 25,500
  • 4
  • 67
  • 82
  • I wouldn't recommend either of these approaches. While employing scoped containers or registering logically named instances are certainly valid techniques for some scenarios, they aren't appropriate given the presumed context of creating new DDD entities. You certainly couldn't predict what new Person objects might need to be created if this is tied to new customer registration, and even if you could ... well, I think you understand the problem that would present. The second option is certainly more viable, but its best to express required dependencies through constructor parameters ... – Derek Greer Oct 08 '09 at 07:47
  • This also doesn't address what I see to be a flaw in the modeling of Person to begin with, and the direct use of the container as a service locator for the creation of such a type. – Derek Greer Oct 08 '09 at 07:51
  • Certainly the scoped container option is the sillier of the two options, but it does work. I also assumed that the OP dumbed down his question and he isn't trying to do anything like this on a simple Entity, but a more complex service object. I have this problem all of the time with these objects where the object has some dependencies, but also needs some instance data passed to it that I need to act on when it is passed. This is why other IoC containers, like Ninject, support exactly what the OP wants. Unity just doesn't yet. – Anderson Imes Oct 08 '09 at 14:08
  • Thanks for your feedback guys. Yes @Imes - I certainly dumbed down the question.. – stiank81 Oct 09 '09 at 07:26
  • My apologies. For some reason I assumed your child container registration of the string "John" was happening at app start up which is why I deemed it impractical. You are correct that this is a viable solution, but I'd still advise against using any container as a service locator in this context. – Derek Greer Oct 15 '09 at 23:21
  • @AndersonImes, I've faced the same issue as the OP and after considering implementing your option 2, I'm left with the feeling that just using properties on the injected object is a more straightforward solution. What advantage, if any, would your Initialize method have over using a setter (or a set of setters) – Frank V May 30 '14 at 13:14
  • @FrankV: Many times it's impossible to do initialization without all of the appropriate data to do the initialization. Simple example. Suppose you want an object that looks up order details. You might need to pass in an IOrderLookupService, an OrderID and a CustomerID. If you use setters, you would have to write code in each setter to determine if all required fields were populated to be able to initialize the object. Seems messy. The alternative is to use NotDan's method, which I would *highly* recommend over mine. Mine is based on an old implementation of Unity :) – Anderson Imes Jun 13 '14 at 06:51
4

There are a few choices you might consider:

In the case where you need to create a new entity which has legitimate dependencies in addition to any data being supplied (e.g. customer name), encapsulate this into a factory which itself has been injected into the calling object:

Person person = _personFactory.CreatePerson("bubba");

The factory can be injected with the entity's dependencies and supplied to the constructor if required or set by other means if optional:

var person = new Person("bubba", _domainService);

For transient-variable dependencies, such as a strategy used by a particular method, use Double Dispatch:

public class Person
{
    public void DoSomethingWith(SomeStrategy strategy)
    {
        strategy.DoSomething(this);
    }
 }

Derek Greer
  • 15,454
  • 5
  • 45
  • 52
  • This is only true if you are assuming Person is just a simple entity, which is valid in this case, but doesn't address this shortcoming in Unity for all cases. Ninject and a few other IoC containers have the ability to do exactly what the OP wants, but Unity does not, leaving us with some pretty limited options. I agree the scoped container is about the nastiest thing ever (I don't do this personally), but it is a solution. – Anderson Imes Oct 08 '09 at 13:54
  • Person is just a fictionous class to simplify this question. In my scenario I don't do this for a domain class, but a ViewModel representation of the domain class. I'm using Prism, and the "Person" view in this case will have to trigger commands to show some sub-data in certain regions, and for that I need the IApplicationCommands. – stiank81 Oct 09 '09 at 07:42
  • @Anderson Imes: I wasn't aware some containers enabled this. I can imagine some cases where this might be useful, but as a whole I still recommend a factory or double dispatch approach over using a container as a service locator, as these approaches preserve infrastructure ignorance. At the very least, you could limit your code's dependency upon direct invocations to the container by encapsulating the container specific technique in the factory. – Derek Greer Oct 15 '09 at 23:32
  • I agree 100% with all of your points. I provided the scoped container solution only because it allows Unity to work like other containers like Ninject. The second solution was meant to be an alternative to using the container at all (this is what I do in my projects where I'm using Unity rather than Ninject). – Anderson Imes Oct 18 '09 at 13:59
  • Revisiting this after some time and some experience (amazing how things change in 2 years), I now believe this is the optimal answer. It reduces the surface area on which knowledge of the container itself is necessary and makes testing that much easier (mocking some of those Unity resolve methods is tricky). You are headed for upvote city, sir. – Anderson Imes Jun 27 '11 at 02:59
0

I can't think of any way to do this with constructor injection. I think you'll need to use property injection for the dependencies (marked with the Dependency attribute) and then either take just the string in the constructor, instantiate yourself, then use BuildUp to wire the dependencies, or make the string a property too that you set manually after Resolve.

Steven Robbins
  • 26,441
  • 7
  • 76
  • 90