tags:

views:

1991

answers:

5

I'm trying the following in Unity:

I have a type with the following constructor

public Type1(Type2 firstDependency, Type3 secondDependency)

When resolving Type1 using Unity, I want to specify the specific instance for Type2 to inject. This specific instance of Type2 is not registered in the container. Type3 is registered in the container and should be resolved as usual.

To be more specific, consider Type1 is a DocumentViewer class. Type2 is a specific Document. Type3 is a SpellingChecker.

I want to be able to resolve DocumentViewer for a Document that is only known at runtime. Multiple DocumentViewer instances for differenct Documents can be created.

How can I do this?

A: 

Here is a quick example I have made, you use RegisterInstance or you can use a Lifetime management Claas

             static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<Type1>();

        container.RegisterInstance<Type2>(new Type2());

        Type1 t = container.Resolve<Type1>();

        Type2 t2 = container.Resolve<Type2>();

        Type3 t3 = container.Resolve<Type3>();

        Console.ReadKey();
    }

    public class Type1
    {

    }

    public class Type2
    {

    }

    public class Type3
    {
        private Type1 t;
        private Type2 t2;
        public Type3(Type1 t, Type2 t2)
        {
            this.t = t;
            this.t2 = t2;
        }
    }

EDIT, I included a type with two parameters in constructor to show it can also be reolved

REA_ANDREW
A: 

I don't want to register the instance of Type2 in the original container. The instance of type2 can be different for different instances of Type1.

My next attempt is to create a child container, and register the specific instance of Type2 there.

A: 

Try using named instances:


IUnityContainer container = new UnityContainer();
container.RegisterType<Type1>();
container.RegisterType<Type2>("Instance 1", new ContainerControlledLifetimeManager());
container.RegisterType<Type2>("Instance 2", new ContainerControlledLifetimeManager());
container.RegisterType<Type3>();

Type1 type1 = container.Resolve<Type1>();
if (type1 == ...)
{
  Type2 instance1 = container.Resolve<Type2>("Instance 1");
}
else
{
  Type2 instance2 = ontainer.Resolve<Type2>("Instance 2");
}


You can do some checks on type 1 and decide which instance of type 2 you will need. Note that the "new ContainerControlledLifetimeManager()" parameter will initialize a singleton instance of the resisted type, so you will always get the same instance of type 2.

Update: Same with interfaces. Hope this helps.


IUnityContainer container = new UnityContainer();
container.RegisterType<TextDocument>();
container.RegisterType<ImageDocument>();
container.RegisterType(typeof (IView), typeof (TextView), "Text", new ContainerControlledLifetimeManager());
container.RegisterType(typeof (IView), typeof (ImageView), "Image", new ContainerControlledLifetimeManager());

IDocument document = container.Resolve<TextDocument>();

IView view = null;
if (document is TextDocument)
{
    view = container.Resolve<IView>("Text");
}
else
{
    view = container.Resolve<IView>("Image");
}

view.Show();

Alexander
RegisterInstance also achieves the Singleton Effect
REA_ANDREW
A: 

If you have a class with multiple constructors, you can decide which constructor is used by the Unity container using the "InjectionConstructor" attribute. This gives you the possibility to set some parameters manually.


public class Test
{
    public Test()
    {
    }

    // Always use the following constructor
    [InjectionConstructor]
    public Test(Type1 type1) : this()
    {
    }

    public Test(Type1 type1, Type2 type2) : this(type1)
    {
    }
}

Alexander
A: 

Use a factory.

public class Type1Factory
{
  private Type3 type3;

  public Type1Factory(Type3 _type3)
  {
     type3 = _type3;
  }

  public GetType1(Type2 type2)
  {
    return new Type1(type2, type3);
  }
}

Call it this way:

// SpellingChecker is subclass of Type3
IUnityContainer container = new UnityContainer();
container.RegisterType<Type3>(typeof(SpellingChecker));

// DocumentViewer is subclass of Type2
Type1Factory factory = container.Resolve<Type1Factory>();
Type1 type1 = factory.GetType1(new DocumentViewer());

This assumes that you are only trying to use Unity to resolve the Type3 dependency, and that you have no control over the constructors in Type1. If you can edit Type1, use Alexader R.'s suggestion to make Unity only resolve the one parameter constructor.

Ray Henry