Unity InjectionConstructor for multiparam constructor overriding only single one
Asked Answered
M

3

44

I have a class with constructor like this:

public class Bar
{
    public Bar(IFoo foo, IFoo2 foo2, IFoo3 foo3, IFooN fooN, String text)
    {

    }
}

I want to register Bar in Unity and provide a value for text:

unity.RegisterType<Bar, Bar>(new InjectionConstructor("123"));

However I can't do this because there is no single parameter constructor for Bar.

Is there a way to provide a value for text without specifying all other parameters as ResolvedParameter<IFooN> etc.. I really don't like it, lot's of code, and every time I change a constructor of Bar I need to add another ResolvedParameter

Microchemistry answered 8/8, 2012 at 14:24 Comment(1)
FWIW, This is so easy in AutoFac out of the box: builder.RegisterType<Bar>() .WithParameter("text", "the text value")Respondence
S
49

Unity can't do this out of the box. The best you can do is:

container.RegisterType<Bar>(
    new InjectionConstructor(
        typeof(IFoo), typeof(IFoo2), typeof(IFoo3), typeof(IFooN), "123"));

Or you can use the SmartConstructor provided by the TecX project. This blog post describes some background.

Registration would look like this:

container.RegisterType<Bar>(new SmartConstructor("text", "123"));
Suzansuzann answered 8/8, 2012 at 19:17 Comment(2)
If you need to pass null instead of "123" you will need to use new InjectionParameter<string>(null)Omura
Using typeof(IFoo) saved me, I couldn't figure out what to pass to the InjectionConstructor.Oxalate
W
0
public void Register<TFrom>(params object[] constructorParams) where TFrom : class
        {
            _container.RegisterType<TFrom>(new InjectionConstructor(constructorParams));
        }
Wentz answered 10/5, 2016 at 0:15 Comment(0)
O
0

I used to do that as described in the answer above (that's using InjectionConstructor). The problem with that is that if the signature of the constructor is changed but InjectionConstructor is not updated, then we will know that only at run time. I think that there is a cleaner way to do that and without getting deep into details of the signature of the constructor. Here is how:

public interface IBar
{
    void DoSomethingWithBar();
}

public interface IMyStringPrameterForBar
{
    string Value { get; }
}

public class MyStringPrameterForBar : IMyStringPrameterForBar
{
    public string Value { get; }
    public MyStringPrameterForBar(string value) => Value = value; 
}

public class Bar : IBar
{
    public Bar(IFoo foo, IFoo2 foo2, IFoo3 foo3, IFooN fooN, IMyStringPrameterForBar text)
    {
    }

    public void DoSomethingWithBar() {}
}

Then when registering interfaces, just add:

unity.RegisterType<IFoo, Foo>();
unity.RegisterType<IFoo2, Foo2>();
unity.RegisterType<IFooN, FooN>();
unity.RegisterInstance(new MyStrignPrameterForBar("123"));
unity.RegisterType<IBar, Bar>();

That's all. if tomorrow Bar needs to take more or less parameters, then after adding or removing extra Foo<N + 1> Unity will still automatically construct Bar.

PS I don't think that interface IMyStringPrameterForBar is actually required. However, I prefer to see only interfaces in Unity registrations because it is much easier to twist them around during tests and/or for any other purpose.

Olive answered 20/9, 2019 at 10:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.