How to apply DI in this situation

Jun 16, 2008 at 9:06 AM
Hi guys,

I have a question about applying of DI in this case.

I wrote a class and want to create an object in its some method using container.

class ClassA
{
  public ClassA()
  {
  }

  public void SomeMethod()
  {
    // want to create an instance of classB here using container
  }
}

class ClassB : IDisposable
{
}

I could find only two solutions how to implement it.

// 1
class ClassA
{
  private IUnityContainer container;
  public SomeClass(IUnityContainer container;
  {
    this.
container = container;
  }

  public void SomeMethod()
  {   
    using (var b =
container.ResolveInstance(typeof(classB))
    {
    }
  }
}

In that case i should inject container, but it's anti-pattern according to the documentation of PicoContainer
http://www.picocontainer.org/container-dependency-antipattern.html

// 2
class ClassA
{
  private IClassBFactory factory;
 
  public SomeClass(IClassBFactory factory)
  {
    this.factory = factory;
  }

  public void SomeMethod()
  {   
    using (var b = factory.CreateInstance())
    {
    }
  }
}

In that case i can inject class factory for class B. But i want to use a container to create instances, not factory.

So both my solutions have limitations.
And I'd like to know what will be the most correct solving of this problem.

Thank you in advance.
Jun 18, 2008 at 1:09 PM
Inject the Factory in the A constructor:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Practices.Unity;

namespace DI
{
    public class A
    {
        Factory<B> Bfactory;

        public A(Factory<B> f) { Bfactory = f; }

        public void SomeMethod()
        {
            B b = Bfactory.Create();
            Console.WriteLine(b.ToString());
        }
    }

    public class B
    {
    }

    public class Factory<T> where T : new()
    {
        public T Create() { return new T(); }
    }
    class Program
    {
        static void Main(string[] args)
        {
            UnityContainer unity = new UnityContainer();
            A a = unity.Resolve<A>();
            a.SomeMethod();
        }
    }
}
Jun 18, 2008 at 3:30 PM
It seems that you reproduced my case 2. But i want to use a container to create instances, not factory.
Jun 18, 2008 at 4:43 PM
The correct solution would be to inject the dependency into the object. This would avoid you having to inject the container or factory.

The very notion of having the object instantiate a dependency in a method is also an anti-pattern when doing DI, so your solutions won't be ideal either.

It sounds like you are trying to lazy-load a dependency, but I don't know why. Perhaps it is very expensive to create the dependency that may be optionally used by the object?

If this is the case, the anti-pattern way would be to inject the container. Depending on the amount of effort, I would personally register an inexpensive proxy for the real service in the container that only instantiates the underlying expensive service if necessary. The beauty of this scenario is that injection occurs like normal and the application is none-the-wiser that it is using a proxy.

Hope this helps,

Dave


David Hayden
Microsoft MVP C#
http://www.davidhayden.com/
Jun 18, 2008 at 10:57 PM
I think that dependency injection should not be restricted only by the injection at the object creation time.
Some objects that should be injected can be expensive resources (e.g. db connection or transaction), so they should be created at the time when they are really needed (in some method that can be executed much later that the object created). However in that case dependencies are not "injected" but my object asks container about them, so container looks like service locator.

Guys from PicoContainer forum (http://www.nabble.com/forum/ViewPost.jtp?post=17859690&framed=y) recommended me the following scheme:

class Main implements ServiceLocator

  PicoContainer pico; 

  Main()
  { 
     pico = new DefaultPicoContainer(); 
     pico.registerInstance(this); 
  }
                
   // implement ServiceLocator.getClassBInstance() 
   ClassB getClassBInstance()
  { 

     return (ClassB)pico.getInstance(ClassB.class); 
  }
}

class classA

   ServiceLocator locator; 
   
  classA(ServiceLocator locator) 
  { 

    this.locator = locator; 
  }
}


Jun 19, 2008 at 12:01 AM
That's really not that different than injecting the container. I think the major difference is to not take a hard dependency on one particular container, but instead on a separate interface that could theoretically be implemented by multiple containers (or just a standalone object).

.NET already has an interface like ServiceLocator - it's System.IServiceProvider. It'd be pretty simple to build an implementation of IServiceProvider that calls into a container.

-Chris
Jun 19, 2008 at 4:37 AM
Edited Jun 19, 2008 at 10:16 AM
Almas,

I agree with Chris. You can't have the Container create the object because you then have a hard dependency.

If you need to create a new object in SomeMethod() and not at construction time, then I think injecting the Factory is the answer. I'm not sure why you don't want to use a Factory.

Ray
http://initializecomponent.blogspot.com
Jun 19, 2008 at 8:32 AM
Because i guess that implementing of factory is almost duplicating of container functionality. Container is also worked as class factory.
But maybe i'm wrong ...
Jun 19, 2008 at 9:47 AM
The point is that if you reference Unity in your component you are introducing a dependency on Unity. You use an IoC container to minimize dependencies and make it easier to reuse your components. You don't want to inadvertently introduce a dependency on Unity.
Oct 15, 2008 at 10:47 PM
Our shop is trying to leap towards TDD.  So, we ran into the same issue real quick.  How do you avoid object instantiation directly within methods?  Factory or Unity? Not all dependencies can be explicitly parameterized in constructor.
Oct 15, 2008 at 11:43 PM

Our shop is trying to leap towards TDD.  So, we ran into the same issue real quick.  How do you avoid object instantiation directly within methods?  Factory or Unity? Not all dependencies can be explicitly parameterized in constructor.

I would use a Factory. You can pass in a mock factory in your unit tests.
Oct 16, 2008 at 2:29 AM
I look at it this way: DI containers are for resolving services, not for resolving entities. So for example, you'd get an ICustomerRepository out of the DI container. You would NOT get a Customer directly out of the container.

The goal isn't to avoid new inside your object per se, it's about avoiding poor coupling. And if you've got something that you need a new instance every time, and you need parameters that vary from instance to instance, a special case factory is the way to go. You'd resolve the factory from the container and then call the factories to get your instances.

Nov 19, 2008 at 4:31 AM
What is the best practice for implementing a factory of objects that are (currently) instantiated through dependency injection?  It seems logical to hand the factory an instance of Unity and resolve objects from there, but according to this discussion it's anti-pattern.  As an example, I want to make a pizza factory like this:

// Pizza.cs
namespace UnityTests
{
    public enum PizzaTopping
    {
        Cheese,
        Pepperoni,
        Olive,
        Mushroom,
        BellPepper,
        Sausage
    }

    public class Pizza
    {
        PizzaTopping[] m_toppings;

        public Pizza(params PizzaTopping[] toppings)
        {
            m_toppings = toppings;
        }

        public Pizza(PizzaTopping topping1, PizzaTopping topping2, PizzaTopping topping3)
        {
            m_toppings = new PizzaTopping[] { topping1, topping2, topping3 };
        }

        public Pizza(PizzaTopping topping1, PizzaTopping topping2)
        {
            m_toppings = new PizzaTopping[] { topping1, topping2 };
        }

        public override string ToString()
        {
            string pizza = "{ ";
            foreach (PizzaTopping topping in m_toppings)
            {
                pizza += Enum.GetName(typeof(PizzaTopping), topping) + " ";
            }
            return pizza + " }";
        }
    }
}
// PizzaFactory.cs
namespace UnityTests
{
    public class PizzaFactory
    {
        public IUnityContainer ConfiguredContainer { get; private set; }

        public PizzaFactory(IUnityContainer container)
        {
            ConfiguredContainer = container;
        }

        public Pizza Create(string pizzaType)
        {
            try
            {
                return ConfiguredContainer.Resolve<pizza />(pizzaType);
            }
            catch
            {
                Console.WriteLine("We don't have that.  Cheese pizza for you!");
                return new Pizza(PizzaTopping.Cheese);
            }
        }
    }
}
But I shouldn't do this because it's anti-pattern (and I can't configure Unity to play along).  What should I be doing instead?  I guess I'm basically pushing the factory's list of valid pizzas to Unity's configuration, but otherwise I need to either configure the PizzaFactory without Unity or I have to hard-code the options.  Do you guys see a better way?
Nov 20, 2008 at 7:54 AM
My suggestion would be to create 2 instances of IUnityContainer.  For example, mainContainer and pizzaContainer.  pizzaContainer will contain the registration for the Pizza class.  The mainContainer will in turn contain a the registration for PizzaFactory and a registered instance of an IUnityContainer which is the pizzaContainer. 

IUnityContainer mainContainer = new UnityContainer();

 

 

IUnityContainer pizzaContainer = new UnityContainer();

 

pizzaContainer.RegisterType<

Pizza>(); -- pass injection members here

 

mainContainer.RegisterInstance<

IUnityContainer>(pizzaContainer);

 

mainContainer.RegisterType<

PizzaFactory>();

 



Sarah Urmeneta

Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com

 

Nov 20, 2008 at 3:30 PM
Craig,

I wouldn't consider your implementation an anti-pattern at all. What you've done is decouple your application from the Unity container through the use of PizzaFactory. Once your configuration code initializes the container, the app doesn't know anything about Unity, it is using PizzaFactory. If you ever want to switch containers, you only will need to change your configuration code and the PizzaFactory.

Ray
http://initializecomponent.blogspot.com