Compartir vía


Circular References with Dependency Injection

Dependency injection mechanisms carry the risk of unintentional circular references, which are not easy to detect or prevent. This topic describes the situations where you may inadvertently cause circular references to occur, resulting in a stack overflow and application error. The most common causes of circular references with dependency injection are the following:

  • Objects generated through constructor injection that reference each other in their constructor parameters
  • Objects generated through constructor injection where an instance of a class is passed as a parameter to its own constructor
  • Objects generated through method call injection that reference each other
  • Objects generated through property (setter) injection that reference each other

For example, the following code shows two classes that reference each other in their constructors.

public class Class1
{
  public Class1(Class2 test2)
  { ... }
}

public class Class2
{
  public Class2(Class1 test1)
  { ... }
}
'Usage
Public Class Class1
  Public Sub New(test2 As Class2)
    ...
  End Sub
End Class

Public Class Class2
  Public Sub New (test 1 As Class1)
    ... 
  End Sub
End Class

It is the responsibility of the developer to prevent this type of error by ensuring that the members of classes they use with dependency injection do not contain circular references.

Note

You could use constructor injection to specify any of a series of constructors or method overloads; however, you could inadvertently cause endless recursion. To avoid the endless recursion, specify which constructor to call in the RegisterType call.

Unity's default behavior is to resolve the constructor with the most parameters. This would cause endless recursion in the following example.

container.RegisterType<IServiceProvider, ServiceContainer>();
var sp = container.Resolve<IServiceProvider>();
'Usage
container.RegisterType(Of IServiceProvider, ServiceContainer)()
Dim sp = container.Resolve(Of IServiceProvider)()

To avoid the endless recursion, specify which constructor to call in the RegisterType call, as in the following example:

container.RegisterType<IServiceProvider, ServiceContainer>(new InjectionConstructor());
'Usage
container.RegisterType(Of IServiceProvider, ServiceContainer) _
          (New InjectionConstructor())

In this case, when creating the service container, the zero argument constructor is explicitly requested.