Hi All,
Can you guess the output of the below program :
using System;
public class Program
{
public static void Main()
{
Console.WriteLine(MethodOne());
}
public static int MethodOne() {
return MethodTwo() * 50;
}
public static int MethodTwo(){
return MethodOne() * 50;
}
}
Congrats, if you have guessed it correctly. Here is the output
System.StackOverflowException: 'Exception of type 'System.StackOverflowException' was thrown.'
And what is the cause of that Exception? Yes, it's circular dependency. MethodOne depends on MethodTwo to finish its execution, whereas MethodTwo depends on MethodOne to finish its execution. And, it's a never ending loop.
Circular Dependency can happen with :
- Functions / Methods
- Classes ( or I can say Types )
- Libraries / Projects
And if you are a guy who is looking for a definition of circular dependency, here is the extract from Wikipedia :
In software engineering, a circular dependency is a relation between two or more modules which either directly or indirectly depend on each other to function properly. Such modules are also known as mutually recursive.
Back to our example above, what we have seen is a circular dependency in the form of a Method ( Functions in some programming languages ).
And here is an example of circular dependency in the form of classes
using System;
public class Program
{
public static void Main()
{
Console.WriteLine(new ClassOne().MethodOne());
}
}
public class ClassOne
{
ClassTwo classTwo = null;
public ClassOne()
{
classTwo = new ClassTwo(); // Notice this
}
public int MethodOne()
{
return classTwo.MethodTwo() * 50;
}
}
public class ClassTwo
{
ClassOne classOne = null;
public ClassTwo()
{
classOne = new ClassOne(); // Notice this
}
public int MethodTwo()
{
return classOne.MethodOne() * 50;
}
}
And the output of the program is the same.
System.StackOverflowException: 'Exception of type 'System.StackOverflowException' was thrown.'
Here, for ClassOne Object to be created - ClassTwo Object should be there, whereas, for ClassTwo Object to be created - ClassOne Object should be there. Again, it's a never ending loop.
I have created objects directly here using new. The behaviour will be the same even if you inject the dependency through Dependency Injection.
And the last one is Cicular dependency in the form of Libraries/ Projects. This happens when you have added ProjectOne as a dependency to ProjectTwo, and ProjectTwo as a dependency to ProjectOne.
Luckily, Visual Studio ( am using VS 2019 ) prevents this from happening by throwing the below error.
But, who can stop people from adding circular dependency by directly editing the project file ( or someone who is using another editor ) :)
Anyways, I feel it would be great if DotNet Compiler can identify this and give us some warnings during compile time ( rather than allowing to have circular dependencies in the program and then application crashes during run-time).
I know there are third-party plugins/ libraries like NDepend that can help us, but I would prefer this feature in the .Net compiler itself.
Now, I have talked so much about Circular Dependency, you might be looking for a solution. The solution lies in your design of the application. Poor design causes these kinds of issues. I always recommend decoupled software design. And if you think, just using any Dependency Injection Container, things are decoupled - you are wrong. DI Containers just takes you one step further when it comes to decoupled architecture. There is a lot more you need to do to ensure that there is no tight coupling and mismanagement of software components.
Your thoughts and comments are always welcome :)