Explicit construtor parameters

Jan 14, 2009 at 8:36 PM
Hi all

I've been looking through the posts and cannot see an answer to my specific problem.  I saw the following text in another post

========================================
public class Student: IPerson
{
    public Student()
    {
    }
    
    public Student(string name, int age)
    {
         .....
    }
}

IUnityContainer container = new UnityContainer();
container.RegisterType<IPerson, Student>(new InjectionConstructor("Student1", 20);
Student student = container.Resolve<Student>();
========================================

However, what I need to do is to pass in specific values.

public ActionResult CreateNew(string name, int age)
{
  var student = Container.Resolve<Student>(.....................................);
}

What I need to do is to pass the name and age as parameters, can this be done?  My exact requirement is more like this:

public class Person
{
  public Person(ObjectSpace objectSpace, ILoggingService loggingService)
  {
    .....
  }
}

var objectSpace1 = new ObjectSpace();
var objectSpace2 = new ObjectSpace();

var person1 = Container.Resolve<Person>(objectSpace1);
var person2 = Container.Resolve<Person>(objectSpace2);

So the ObjectSpace parameter would be set to the value passed, and the ILoggingService would be resolved.  Without this ability it is going to be very difficult for me to use Unity for my requirements, so I *really* hope something is possible.  Another thing to consider is that my container is running on a website and therefore being hit by multiple threads at the same time so I can't configure then resolve either.

Thanks

Pete
Jan 14, 2009 at 11:57 PM
Passing parameters in the Resolve call is not currently supported. It's been discussed a little bit, but not much beyond "it'd be nice to have this."

It's under consideration, but once you start digging in it's a real can of worms.

Jan 15, 2009 at 10:57 AM
I think I will instead keep my constructors as they are.  I'll see if there is a generic place within my framework that will let me call BuildUp


Thanks

Pete
Jan 16, 2009 at 3:00 PM
Hi,
Any pointer to some best practice work around for such a requirement? Or possibly any DI container that implements this feature?

Say you have multiple parsers (could be commands, actions, ...) that are being passed a string to parse.
IUnityContainer container = new UnityContainer();
container.RegisterType<IParser, ParserA>("ParserA");
container.RegisterType<IParser, ParserB>("ParserB");
container.RegisterType<IParser, ParserB>("ParserC");
etc...

...
string parseType = IdentifyNeededParser();
IParser myParser = container.Resolve<IParser>(parseType); <---- also need to pass a string to parse.
string parsedResult = myParser.ParsedData();
...

One could argue that the parser could possibly be more generic and not being passed a string on constructor... well may be ... there are anyway some cases where this typical scenario is needed.

Thanks
Jan 19, 2009 at 5:26 AM
I'm not sure what the performance implications would be in your application, but you could use a child container like so:

public class PersonFactory : IPersonFactory
{
    private IUnityContainer container;

    public PersonFactory(IUnityContainer container)
    {
        this.container = container;
    }

    public Person Create(ObjectSpace objectSpace)
    {
        var child = container.CreateChildContainer();
        child.RegisterInstance<objectSpace>(objectSpace);
        return child.Resolve<Person>();
    }
}
Jan 19, 2009 at 8:57 AM

Hi

I considered this approach but couldn't think where I can release the child container.  Something that doesn't need a programmer to remember to do it would be good, I suppose I could put it in the EcoSpace.Dispose() - would that be a good or bad practise?

Jan 19, 2009 at 2:17 PM
I prefer to use Abstract Factory pattern in this situation.
So i'd create student instances using specific factory implementation. But factory type can be registered in the container in the usual way.
Jan 19, 2009 at 5:33 PM
Well, you could make PersonFactory disposable:

 public class PersonFactory : IPersonFactory, IDisposable
{
    private IUnityContainer container;
    private IList<IUnityContainer> childContainersToDispose;

    ...

    public Person Create(ObjectSpace objectSpace)
    {
        var child = container.CreateChildContainer();
        child.RegisterInstance<ObjectSpace>(objectSpace);
        childContainersToDispose.Add(child);

        return child.Resolve<Person>();
    }
}

But then you have to deal with it one level up. Or you could just dispose of the child container right away if ObjectSpace is not disposable, but then you create a hidden restriction that ObjectSpace cannot be disposable in the future (not great, just throwing ideas out there).

    public Person Create(ObjectSpace objectSpace)
    {
        using (var child = container.CreateChildContainer())
        {
            child.RegisterInstance<ObjectSpace>(objectSpace);
            return child.Resolve<Person>();
        }
    }

Or if Person is disposable, you could make a person decorator that disposes of the child container too:

    public Person Create(ObjectSpace objectSpace)
    {
        var child = container.CreateChildContainer();
        child.RegisterInstance<ObjectSpace>(objectSpace);
        var person = child.Resolve<Person>();

        return new PersonDecoratorThatDisposesOfChildContainerToo(child, person);
    }

Again, just throwing stuff out there to spark some discussion :)