11

I'm trying to use an IOC container to create the initial object graph within my application.

I have a MainForm. This form depends on a MenuStrip, which depends on multiple MenuStripItems. Some MenuStripItems depend on the MainForm.

At the moment I setup all dependencies for constructor injection. Obviously, resolving the MainForm now results in a stack overflow, since the MenuStripItem dependencies of the MainForm try to resolve the Mainform, etc etc...

What's the best way to resolve this circular dependency?

Gerrie Schenck
  • 22,148
  • 20
  • 68
  • 95
  • 1
    I'm curious how you handled the circular reference before you involved the IOC container... Do you have a unit test that hands the form all of its dependencies? – JasonTrue Jan 27 '09 at 07:49
  • Before using IOC, my MainForm would be globally accessible using a Singleton. –  Jan 27 '09 at 08:18
  • Some references on circular dependencies: https://stackoverflow.com/a/37445480/1371329 – jaco0646 Oct 23 '18 at 13:30

7 Answers7

5

Circular dependencies are a sign of bad design, no matter if you are using IoC or not. I suggest that you do a redesign to avoid it. Adding a helper object may be a solution.

For example, make the MenuStripItems depend only on one part of the MainForm that is necessary for them and not on the whole.

kgiannakakis
  • 103,016
  • 27
  • 158
  • 194
3

I agree with kgiannakakis:

Circular dependencies are a sign of bad design, no matter if you are using IoC or not. I suggest that you do a redesign to avoid it. Adding a helper object may be a solution.

To find out which methods should be extracted into the helper class, this process may help:

Given you have a class A and a Class B which reference to each other and create a circular dependency. To find out which methods to extract into an external helper oject, list all of the methods in your class A used by class A, and all the methods in your class B used by class A. The shorter of the two lists is your hidden helper class C.

Inspired by Miško Hevery http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-and-dependency-injection/

Andreas
  • 2,045
  • 5
  • 19
  • 30
3

Make a controller class which provides the data and logic which the MainForm and MenuStripItem both needs to avoid the circular reference.

Gerrie Schenck
  • 22,148
  • 20
  • 68
  • 95
2

You need to create a dealer class (or interface) containing reference of both classes you are using them. You should use this dealer class (or interface) rather than each reference classes you tried to use them before.

Explaining the solution:
Consider 3 classes as following:

public Class A {
    public Method CommonMethod(){
        //Some implementation...
    }

    Method C(){
        //CommonMethod form class B are using here
        B obj = new B();
        B.CommonMethod();
    }
}


public Class B {
    public Method CommonMethod(){
        //Some implementation...
    }

    Method D(){
        //CommonMethod form class A are using here
        A obj = new A();
        A.CommonMethod();
    }
}


public Class DealerClass {
    private readonly A _inctanceA;
    private readonly B _inctanceB;

    //Cunstructor method of the class
    DealerClass(A inctanceA, B inctanceB){
        _inctanceA = inctanceA;
        _inctanceB = inctanceB;
    }

    //Using CommonMethod of class A
    public UsingCommonMethodA(){
        _inctanceA.CommonMethod();
    }

    //Using CommonMethod of class B
    public UsingCommonMethodB(){
        _inctanceB.CommonMethod();
    }    
}

So according to this solution you should use methods of other classes that have circular dependency to each other in the DealerClass.

Milad Rashidi
  • 1,296
  • 4
  • 22
  • 40
2

You can use a setter for injecting some of the dependencies after construction.

starblue
  • 55,348
  • 14
  • 97
  • 151
1

I don't see how creating a helper class or controller solves the circular dependency problem.

I'll give some more details. The MenuStripItems depend on MainForm because they can set the Content of the MainForm. Following the above suggestions, let's say I create a seperate interface for the MainForm Content, IFormContent. MenuStripItem can then depend on IFormContent. But an implementation of IFormContent will then again depend on MainForm, resulting in a circular dependency.

Perhaps I should resort to setter injection somewhere instead of constructor injection?

  • 1
    You have a controller class with one property: Content. MenuStripItem sets the Content property on the controller, and MainForm reads it. So these two classes reference the controller, but the controller knows nothing about the two GUI classes. So no circular reference. – Gerrie Schenck Jan 27 '09 at 09:22
0

How are the MenuStrip and MenuStripItems created?

When I've used IOC, there is always a 1-to-1 relationship between a service and the dependencies which the IOC container provides for the service. If a service needs more than one of something, it would then have a 1-to-1 relationship with a single factory object that creates the multiple items. This factory method could be parameterized to allow the created items to refer back to their container.

Frank Schwieterman
  • 24,142
  • 15
  • 92
  • 130