17

Problem:

Assume the class:

public class MyAwesomeClass
{
   private IDependCls _dependCls;
   public MyAwesomeClass(IDependCls dependCls)
   {
       _dependCls = dependCls;
   }

}

And somewhere else I need to get an instance of that class, like so:

public class SomewhereElse
{
    public void AwesomeMethod()
    {
        //...
        // AwesomeStuff
        //...

        var GetErDone = new MyAwesomeClass();  // PROBLEM! No constructor with 0 arguements
    }
}

Question is, do I

Proposed solution 1:

A) have to make an extra constuctor that resolves the dependency? For example:

   public MyAwesomeClass() // new constructor
   {
       _dependCls = DependencyResolver.Current.GetService<IDependCls>();
   }


public class SomewhereElse
{
    public void AwesomeMethod()
    {
        var GetErDone = new MyAwesomeClass();  // IT WORKS!!
    }
}

Proposed solution 2:

B) use the resolver inside AwesomeMethod right before var GetErDone

public class SomewhereElse
{
    public void AwesomeMethod()
    {
        var depCls = _dependCls = DependencyResolver.Current.GetService<IDependCls>();
        var GetErDone = new MyAwesomeClass(depCls);  // IT WORKS!!
    }
}

Autofac solution?

C) Some other Autofac way?

Looking for best practices, as well as a good Autofac solution if possible. I think the first way is the worst as optional dependancies could lead to a lot of clutter.

Summary:

How do I get a new MyAwesomeClass() when MyAwesomeClass has dependencies?

Mihalis Bagos
  • 2,500
  • 1
  • 22
  • 32
  • Do you really mean _optional_ when you say it? If it really is optional, you may want to look into property injection. If not, and your ctor is cluttered because of too many dependencies, maybe your class is doing too much (see also [this answer](http://stackoverflow.com/a/2420245/1282778)). – Filippo Pensalfini May 29 '12 at 12:48
  • I don't have a question about constructor clutter, rather than creating an instance of a class that needs constructor injection. – Mihalis Bagos May 29 '12 at 12:57
  • Thanks for not posting the solution answer. Not like any body else has this issue... /s – Martin Dawson Nov 28 '17 at 21:10

6 Answers6

11

Have a look at the Composition Root pattern.

You are right, pulling up the dependency resolution only moves the problem to another place. If you continue to move it upwards in your object graph, though, you will reach the entry point of your application. There you will compose your object graph.

Compare that to the Service Locator anti-pattern (using DependencyResolver in client classes in your case) and you will see that Composition Root is a superior solution.

Filippo Pensalfini
  • 1,714
  • 12
  • 16
  • Thanks for the reply. +1 because you actually have a grasp on the concept, and thanks for your article. So I guess this will happen inevitably? I am going to read on this approach more but I think that the actual composition root as you call it should be the declaration of the binding itself. Otherwise, you break both the single responsibility and the separation of concerns rule. – Mihalis Bagos May 29 '12 at 14:53
  • Yes, the Composition Root is defined abstractly as a "location", you can split it in several classes, but it is important that they are contained in the same assembly. Mark Seemann, the author of the articles, wrote [a great book](http://www.amazon.com/Dependency-Injection-NET-Mark-Seemann/dp/1935182501) about DI btw. – Filippo Pensalfini May 29 '12 at 15:04
  • 1
    @Mihalis - Did you ever get a satisfactory solution using the Composition Root pattern or otherwise. You example code is easy to follow and I would like to see the code for the 3rd solution - thans – Peter Kerr Feb 10 '15 at 10:20
  • I think everyone would probably agree that using DI in the constructor as Seemann more or less explains seems to be the best solution. However there are instances where you might need to dynamically get an instance of a controller at which point you would need a parameterless contstructor and then the Service Locator would seem to be our only option? – ewahner Sep 24 '15 at 14:50
  • 1
    No Examples + dead link + OP never posted an answer = terrible question/answer. – Martin Dawson Nov 28 '17 at 21:06
  • @MartinDawson Both links seem to be working from here. What example would you have liked to see? – Filippo Pensalfini Nov 29 '17 at 07:49
1

First of all apart from constructor injection you can also use property injection and method injection. However constructor injection is most common and the fastest method so I suggest to stick to it.

The second thing you need to do is to register your MyAwesomeClassin the Autofac container along with its dependency, they have some nice examples right at their home page.

And the last thing - you should not create instances of MyAwesomeClass directly - use Autofac instead. Here is an updated example:

public void AwesomeMethod()
{
    //...
    // AwesomeStuff
    //...

    var GetErDone = DependencyResolver.Current.GetService<MyAwesomeClass>();
}
Sergey Rybalkin
  • 3,004
  • 22
  • 26
1

You can create a new instance of 'MyAwesomeClass' with reflection, resolving the constructor parameters with Autofac.

    public static T Instance<T>() where T : class
    {
        Type instanceType = typeof(T);
        ConstructorInfo constructorInfo = instanceType.GetConstructors()[0];
        ParameterInfo[] constructorParamsInfo = constructorInfo.GetParameters();
        object[] constructorParams = new object[constructorParamsInfo.Length];

        for (int i = 0; i < constructorParamsInfo.Length; i++)
        {
            var parameterInfo = constructorParamsInfo[i];
            var type = parameterInfo.ParameterType;
            constructorParams[i] = Container.Resolve(type);
        }

        object instance = Activator.CreateInstance(instanceType, constructorParams);

        return (T)instance;
    }
Jose Aviles
  • 111
  • 1
  • 2
0

If you want to resolve instance automatically via Autofac, you can only choose from this

  • Inject in constructor of your class
  • Inject in property, by using

    var builder = new ContainerBuilder();

    builder.RegisterType<Foo>().PropertiesAutowired();

  • Use global access by DependencyResolver.Current.GetService<IFoo>();

Vitaly Zemlyansky
  • 331
  • 1
  • 3
  • 12
  • 1
    I am using constructor injection but I am asking about the actual process of creating an instance of that class. – Mihalis Bagos May 29 '12 at 12:56
  • What do you mean process of creating an instance of that class ? What class do you want to instantiate ? And what exactly do you want to do ? Prodide more information – Vitaly Zemlyansky May 29 '12 at 13:12
  • Please see the second gray block. If I use the code as is, I get a problem (of course). Then, I propose 2 solutions which I don't like, and ask for a third - or a confirmation that one of the 2 I propose is standard practice. I will update the answer to actually include my solutions for you to see – Mihalis Bagos May 29 '12 at 13:14
  • If you want instantiate MyAwesomeClass inside method, the best way is using DependencyResolver. But, I think it's bad practise to instantiate something in your method. You should create interface IMyAwesomeClass and use ctor injection in class using it. After that you can use class field in you method – Vitaly Zemlyansky May 29 '12 at 13:25
  • Yes, DependencyResolver can be used in 2 different places (the solutions I am proposing). However, I would like a solution that doesnt involve DependencyResolver. About an interface, please see me comment on @Peter Lillevold answer. The problem stays the same, just one level higher. ( `SomewhereElse` class will NEED to get `new SomewhereElse()` at some point, so same problem there) – Mihalis Bagos May 29 '12 at 13:32
0

In the class containing MyAwesomeMethod take MyAwesomeClass as a constructor dependency. Autofac will take care of the instantiation.

Peter Lillevold
  • 33,668
  • 7
  • 97
  • 131
  • 1
    yes but this just move the problem one class higher up, this is the point I am actually. What if I want to make an instance of the class containing `MyAwesomeMethod` ? – Mihalis Bagos May 29 '12 at 13:27
0

I know that this question is old, but I found a quite useful link on the autofac documentation describing dynamic instantiation of classes.

Autofac Dynamic Instantiation

Perhaps it could be helpful for someone.

Community
  • 1
  • 1
canvee
  • 361
  • 4
  • 12