Is there a way of automatically assigning constructor-injected dependencies to their equivalent member variables based on name convention (a la AutoMapper) with Autofac?
No, not unless you build it yourself. Autofac is only compatible with standard OOP practices, which do not include using Reflection to populate private member variables.
When implementing the Dependency Injection pattern in C# there are 3 different ways that dependencies can be injected:
- Constructor Injection
- Property Injection (also called Setter injection)
- Method Injection
There is no accepted pattern for injecting private
member variables. In fact, this cannot be done with standard OO principles, in .NET it can only be accomplished using Reflection.
Also, when using the the Dependency Injection pattern, there is no rule that says you must use a DI container such as Autofac. In fact, the use of a DI container is completely optional when applying the DI pattern. For example, when making unit tests it is easy to use the pattern without Autofac - here is an example that uses NUnit and Moq.
[Test]
public void TestDoSomething()
{
// Arrange
var foo = new Mock<IFoo>();
var bar = new Mock<IBar>();
var baz = new Mock<IBaz>();
var target = new MyClass(foo.Object, bar.Object, baz.Object);
// Act
var result = target.DoSomething();
// Assert
Assert.IsNotNull(result);
// Test other conditions
}
On the other hand, if you add this extra bit of Reflection, you would need access to it in order to populate your MyClass
with dependencies.
[Test]
public void TestDoSomething()
{
// Arrange
var foo = new Mock<IFoo>();
var bar = new Mock<IBar>();
var baz = new Mock<IBaz>();
var target = new MyClass();
// Use Reflection to insert the dependencies into the object
InjectDependencies(target, foo.Object, bar.Object, baz.Object);
// Act
var result = target.DoSomething();
// Assert
Assert.IsNotNull(result);
// Test other conditions
}
A big concern here is that the code will compile fine if you completely remove the InjectDependencies(target, foo, bar, baz);
line and you will probably end up with a NullReferenceException
at runtime somewhere in your class. The purpose of an instance constructor is:
to create and initialize any instance member variables when you use the new expression to create an object of a class.
This guarantees the object is correctly constructed with all of its dependencies. A typical example of the DI pattern with constructor injection:
public class MyClass
{
private readonly IFoo _foo;
private readonly IBar _bar;
private readonly IBaz _baz;
public MyClass(IFoo foo, IBar bar, IBaz baz) {
_foo = foo ?? throw new ArgumentNullException(nameof(foo));
_bar = bar ?? throw new ArgumentNullException(nameof(bar));
_baz = baz ?? throw new ArgumentNullException(nameof(baz));
}
}
The above example uses the readonly
keyword and guard clauses in the constructor (which are missing from your example) to guarantee the instance of MyClass
cannot be created unless all of its dependencies are supplied. In other words, there is a 0% chance that any of the member variables will ever be null
, so you will not have to worry about increasing the complexity of the code by adding null
checks to the rest of the class. There is also a 0% chance that any code outside of the constructor can change any of the dependencies, which could cause hard-to-find stability issues with the application.
The bottom line is, you could use Reflection to populate your classes this way if you would like to build your own Autofac extension and write null
checks throughout your class, but I wouldn't recommend it because you are taking something that is achieving loose coupling with pure OOP and turning it into a tightly-coupled piece of Reflection code that all of your classes (and anyone who uses them) will depend upon.
You are also removing the possibility of using the handy features of C# that guarantee that the instance will always have all of its dependencies regardless of the context in which it is used (DI container or no DI container) and that they cannot be unwittingly replaced or set to null
during runtime.
Workaround
If your primary concern about "boilerplate code" is that you have to type the constructor code yourself, here are a couple of Visual Studio extensions that automate that part:

Unfortunately, neither one of them seems to add the guard clause to the constructor.