3

I have an Order class with the below constructor

public Order(IProduct product, short count)
{
this._product = product;
this._count = count;
}

I'm trying to setup Unity IoC container and obviously to construct the order object I'd need to know the count and product but these are determined at run time; the count could be any value and product can be any product e.g. Carrot, Melon, etc.

So how to apply IoC for this?

One approach I thought was that my constructor only accepts object dependencies then any other required property to be added using a new Initialize() method:

public Order (IProduct product)
{
this._product = product;
}

public Initialize(short count)
{
this._count = count;
}

in this way whoever creates the Order object, has to call the Initialize() method afterwards so that other properties that can't be handled by the IoC container be added to it.

Is it the approach that you recommend/use?

The Light
  • 26,341
  • 62
  • 176
  • 258
  • 1
    possible duplicate of [Is there a pattern for initializing objects created via a DI container](http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container) – Mark Seemann Sep 30 '11 at 14:58
  • not exactly and indeed they have introduced a new level of dependency inside the MyIntFactory class: public MyIntfFactory : IMyIntfFactory { public IMyIntf Create(string runTimeParam) { return new MyIntf(runTimeParam); } } – The Light Sep 30 '11 at 15:09
  • I'm amazed why people uprated that answer as the whole idea was that object instantiation shouldn't happen inside the application but from the Unity and that approach just adds a new complexity and violates it. – The Light Sep 30 '11 at 15:12
  • 2
    You might want to refer to this discussion: http://stackoverflow.com/questions/4835046/why-not-use-an-ioc-container-to-resolve-dependencies-for-entities-business-object – Mark Seemann Sep 30 '11 at 15:19
  • 2
    @William, object instantiation happens all over an application. "Newing up" your entities is not what you are trying to avoid with DI. Count is an integer, not a dependency. – scottm Sep 30 '11 at 16:03

4 Answers4

6

This doesn't seem like an appropriate situation for an IoC container to me. Presumably Orders can be instantiated regularly with different Products (and counts) throughout the life of the application based on the behavior of the user, which suggests a container would need to be configured for each context in which Orders might be created - that is, for each Product page.

IoC containers work best when you can make decisions about dependencies seldom and early on, say at application start-up. If the decision on which dependency to inject always takes place at about the same time as the creation of the dependent object, then an IoC container just adds unnecessary complexity.

ladenedge
  • 13,197
  • 11
  • 60
  • 117
  • don't forget the purpose; to make the classes testable. so IoC container to me is just a place where I initialize my dependencies. – The Light Sep 30 '11 at 14:59
  • 4
    @William, the purpose of DI is not to make the classes testable, that is just a side benefit. The purpose is to reduce coupling and promote extension. – scottm Sep 30 '11 at 15:03
1

With Unity you should be able to set up a ParameterOverride to pass in your extra parameters :

container.Resolve<IOrder>(new ParameterOverrides { { "Count", 1 } });

Ok, alternatively create a factory class :

class OrderFactory : IOrderFactory
{
    public OrderFactory ( IProduct product );
    public Order GetOrder (count)
    {
        return new Order ( product, count );
    }
}

Use the container to resolve the factory. Then use the factory to resolve your orders.

Mongus Pong
  • 11,337
  • 9
  • 44
  • 72
  • I'd rather my approach to this; it would be ugly to use container inside application classes. – The Light Sep 30 '11 at 14:55
  • after some thought I have to agree with @William here - The code above required both IOrder and Order to be known, which somewhat defeats part of the point with IoC/DI here. Your app shouldn't know about the concrete Order since this is injected at runtime. Check out the xml config at http://blog.janjonas.net/2011-07-03/asp_net-mvc_3-unity_2-xml-configuration-design-time – Adam Tuliper Oct 01 '11 at 01:56
  • 1
    Also the second example should really use an abstract factory. Have made it implement an interface to make this more clear. The container is set up to resolve this factory. The container doesnt need to know about Order. The app doesn't need to know about either concrete implementation. – Mongus Pong Oct 03 '11 at 08:52
  • Err, did anyone else not notice the obvious IoC breach with a `new Order` being created in `GetOrder`? – Ash Mar 06 '18 at 22:44
0

Count should probably just be a property of Order. What does count represent? The number of order lines or the quantity of product? I'm not quite sure how you plan on implementing and IoC container here.

Something like this:

public class Order
{
  private IProduct _product;
  public Order(IProduct product)
  {
    _product = product;
  }

  public int Count {get;set;}
}
scottm
  • 27,829
  • 22
  • 107
  • 159
  • imagine Count is any property whose value can't be determined by IoC container but it's a must property for the Order class to work. – The Light Sep 30 '11 at 14:56
  • @William, can you show how you are registering and resolving Order and Product? – scottm Sep 30 '11 at 15:04
  • I'm using asp.net web forms and use MVP. my dependencies are resolved on the page level and passed to the presenter. the names I'm using are very different to Order and Product; they were used here for simplicity sorry but the point is how to manage such must dependencies which can't be injected from IoC. – The Light Sep 30 '11 at 15:33
0

@scottm This is the actual code that I have in my aspx page:

private IStoresRankingReportPresenter _presenter;

     protected void Page_Init(object sender, EventArgs e)
            {
                this._presenter = ServiceLocator.Current.GetInstance<IStoresRankingReportPresenter>();

                this._presenter.Initialize(this, this.Count);

                this._presenter.OnPageInit();
            }
The Light
  • 26,341
  • 62
  • 176
  • 258