Question

Does Simple Injector allow you to pass parameters to constructor when you resolve? I'd like to know if both these frameworks do what Unity's ResolverOverride or DependencyOverride both do.

Was it helpful?

Solution

I suspect that this question is about passing primitive values to the constructor at the time the service is actually resolved.

Let's set up a simple test class:

public interface IFoo
{

}

public class Foo : IFoo
{
    public Foo(string value)
    {

    }
}

The Foo class takes a string argument that we would like to supply when resolving the IFoo service.

var container = new ServiceContainer();
container.Register<string, IFoo>((factory, value) => new Foo(value));
var firstFoo = container.GetInstance<string, IFoo>("SomeValue");
var secondFoo = container.GetInstance<string, IFoo>("AnotherValue");

If we want to be able to create new instances of the Foo class without using the container directly, we can simply inject a function delegate.

public interface IBar { }

public class Bar : IBar
{
    public Bar(Func<string, IFoo> fooFactory)
    {
        var firstFoo = fooFactory("SomeValue");
        var secondFoo = fooFactory("AnotherValue");
    }
}

The "composition root" now looks like this:

var container = new ServiceContainer();
container.Register<string, IFoo>((factory, value) => new Foo(value));
container.Register<IBar, Bar>();
var bar = container.GetInstance<IBar>();

If the question is about passing a "static" primitive value to the contructor, this is simply done by registering a factory delegate like this.

var container = new ServiceContainer();
container.Register<IFoo>((factory) => new Foo("SomeValue"));
var firstInstance = container.GetInstance<IFoo>();
var secondInstance = container.GetInstance<IFoo>();

The difference is that this approach does not let you pass a value at resolve time. The value is statically specified at registration time.

OTHER TIPS

Probably the easiest option with Simple Injector is to register with a delegate

[Test]
public void Test1()
{
    Container container = new Container();

    container.Register<IClassWithParameter>(() => new ClassWithParameter("SomeValue"));

    var result = container.GetInstance<IClassWithParameter>();
}

public interface IClassWithParameter { }

public class ClassWithParameter : IClassWithParameter
{
    public ClassWithParameter(string parameter)
    {
    }
}

An advanced option for injecting primitive dependencies is detailed here

The above will all work if your constructor does not have any other dependencies (or you want to resolve these dependencies manually). If you have the scenario below though it falls down:

public class Test : ITest
{
   private IFoo _foo;
   public Test(string parameter, IFoo foo)
   {
      _foo = foo;
      ....
   }
}

Now you not only have to manually inject the string but also Foo. So now your not using dependancy injection at all (really). Also Simple Injector state:

Simple Injector does not allow injecting primitive types (such as integers and string) into constructors.

My reading of this is that they're saying "don't do this".

Extensibillity points

Another option here is to use "Extensibillity points" for this scenario.

To do this you need to abstract your hard coded elements from your injected elements:

public class Test : ITest
{
   private IFoo _foo;
   public Test(IFoo foo)
   {
      _foo = foo;
      ....
   }

  public void Init(string parameter)
  {

  }
}

You can now inject your dependanices and your hardcoded elements:

_container.Register<ITest, Test>();
_container.RegisterInitializer<Test>(instance => {instance.Init("MyValue");});

If you now add another dependancy, your injection will now work without you having to update the config, i.e. your code is nicely de-coupled still:

public class Test : ITest
{
   private IFoo _foo;
   private IBar _bar;
   public Test(IFoo foo, IBar bar)
   {
      _foo = foo;
      _bar = bar;
      ....
   }

  public void Init(string parameter)
  {

  }
}

In response to Liam's answer I would like to point out that there is a simpler way of doing this.

If you have the following situation:

public class Test : ITest
{
   private IFoo _foo;
   public Test(IFoo foo, string parameter)
   {
      _foo = foo;
      ....
   }
}

You could write your ioc configuration as below

_container.Register<IFoo, Foo>();
_container.Register<ITest>(
    () => new Test(
        _container.GetInstance<IFoo>(),
        "MyValue"
    )
);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top