DIY Property Injection (Xamarin / .Net)
In this article, we will examine how Property Injection differs from Constructor Injection and implement the former in addition to the latter based on a small DI container in the source.
This is an entry-level learning material. It will be useful for those who are not familiar with DI containers or are interested in how it is arranged from the inside.
Dependency Injection is a common design pattern used to create programs with loosely coupled components. Beginners usually meet him on projects where unit tests are used.
A classic example of a system with tight connectivity is when a hairdryer is tightly connected to a power supply in a hotel (the owners worry about the safety of the device). The length of the wire, in general, is enough, but with this approach it is impossible to modify the hair dryer separately from the wall, and the wall - separately from the hair dryer. The introduction of loose coupling in the form of a socket and a plug solves this problem.
Another example is the tight binding of employees to the workplace, and also the need to go to work every day. This tight connection in modern companies is increasingly weakened by both the ability to work from home and the introduction of the practice of lack of a permanent workplace: if you want to come to the office - do not forget to pop a place. From the point of view of the employer, the work will be performed regardless of the seat of the employee. Of course, additional risks arise, but such is the price of greater flexibility.
The idea of implementing dependencies in the narrow sense is that the consumer class of a certain function does not access the provider class directly, by creating an instance of it, but indirectly, by reference of a certain interface type. The provider class is only required to conform to the specified interface.

Unlike the service locator, here the classes not only do not know anything about each other, but also do not contain access to the intermediary class (service locator).
In order to match a particular class (or class instance) to an interface, the so-called DI container is often used, in which the interface and implementation relationships are registered in advance. For languages that do not support reflections, that is, do not allow to operate on type properties, you can restrict yourself to a template such as composition root (consideration of this template is outside the scope of this article).
This approach provides flexibility: you can always use another, instead of one implementation of the interface, according to the circumstances.
The natural way to pass references to the consumer class is to specify them in the parameters of its constructor. As a rule, a DI container, upon request of the required interface, automatically runs through the list of parameters and recursively satisfies all the dependencies.
Another way is to pass links through properties, which is called Property Injection. To satisfy the links, the DI container goes over the list of properties and assigns the necessary links to those that meet certain criteria.
There is also a rarer method - Method Injection, where links are passed through a special method (for example, Init () listing the dependencies in the form of parameters). This approach is similar to constructor injection, but it works after creating an instance of the object. This term also means something completely different, namely the simple transfer of dependencies as parameters to an arbitrary method.
There are many DI containers (e.g. Unity, NInject, Autofac, Spring, Castle Windsor, TinyIoc, MvvmCross). Most of them support Property Injection.
But sometimes there are situations when, for one reason or another, a third-party DI container is not suitable for you, and you have to write your own.
For example, corporate policies prohibit the use of third-party libraries. Or the libraries you need do not exist in nature. Or these libraries do not meet design requirements.
In this case, it is not difficult to make your own container - unless, of course, it is technically possible within the framework of the applied development technology, as is possible in .Net.
Dependency injection through constructor parameters requires creating utility variables in the consumer class, in which references from constructor parameters are stored. This is a routine operation, which, in a good way, could be somehow automated. But while there is no such automation, the programmer has to do this work. Each new dependency is added first to the constructor parameters, then to the service variables, then in the constructor a line of assignment of one to another is added.
It is often possible to observe how any of the added parameters is stretched through the code, from the top-level class to the final consumer down the inheritance hierarchy. The chain of calls stretches like a bunch of sausages, from constructor to constructor. Not only is the serial transmission of these parameters in itself cluttering up the code. So also the addition of the next parameter at the end of this chain of calls requires its modification throughout. Which is completely inconvenient. As a result, the class can solidly “swell” only because of all this machinery, without even starting to do anything.
Why not save the programmer from this routine and delegate the creation of entities to a DI container?
It can also be noted that when passing parameters to the constructor, they are usually passed without specifying the parameter name. That is, the user of the class is forced to rely either on the serial number of the parameter, or explicitly indicate the parameter name, which will further clutter up the code.
There is a good rule that if it becomes inconvenient for you to add another dependency to the constructor parameters, then it means that there really are too many of them, and you should review the design. Usually this is 5 pieces - the natural limit of objects that a person without training can hold in his area of attention.
However, we believe that the key word in this rule is inconvenient. I would like to avoid it.
The implementation of the simplest DI container is easy to find in the source. The author once used a small example from Xamarin University (see here ).
Much is lacking here compared to industrial DI containers (singletones, domains, etc.), but this is beyond the scope of this article.
The container allows you to register the relationship between the interface and the implementation (the Register method in different versions, which simply adds an element to the Dictionary), then, in the Resolve method, create an instance of the class that corresponds to the requested interface and do the same parameters of its constructor.
This container works on the basis of Reflections and the method Activator.CreateInstance (). The last method is used to create an instance of a class by its type, and reflections allow you to subtract type properties.
To implement property injection, we will add a special attribute with which we will mark those properties that the container should process as dependencies.
Name the attribute “ResolveAttribute”. To do this, create a System.Attribute descendant class (see Appendix A).
Add attribute processing in the Resolve method of the container.
This is all that needs to be done in the source container in order for dependency injection through properties to work (for the sources, see Appendix B).
Suppose there is a class in which it is used to inject dependencies through the constructor (of course, dependencies must be registered in advance - see Appendix C). Note that the parameters and constructor body are purely serving code:
We modify the class using the implementation through the properties:
As you can see, the amount of utility code has decreased, and the code itself has become more readable.
The flip side to success is the reduced ability to control the integrity of the program by the compiler. However, this is a common consequence for all types of IoC implementations.
It should also be borne in mind that it is considered normal practice to use constructor injection for mandatory dependencies, and property injection for optional ones. That is why the properties in our example have a public access modifier.
Public access to dependencies makes it possible to replace their values from the outside, which, on the one hand, serves as a tool for introducing dependencies manually, and on the other hand, it allows you to inadvertently damage the work of the entire class if it is not written correctly enough.
The code in our implementation does not check the access level of the property, that is, you can use either “public” or “private”. The latter is recommended for those properties whose arbitrary modification is undesirable. This will protect the class from inadvertent misuse and, at the same time, allow the use of property injection.
As you can see from our implementation, to support Property Injection, you need to go through all the properties of the class using reflections. It may turn out that there are a lot of properties - in practice, there are more than a thousand, which somewhat slows down the program.
For this reason, this approach is not very suitable for classes with a large number of properties. Here optimization is possible both from the user code and from the container itself.
For example, it would be possible to shorten the list of properties by putting in the service class those that are not marked “ResolveAttribute” (in our implementation), think about deferred reading (lazy loading). And the container could cache the list of properties for implementation. But we'll talk about this some other time.
At the same time, Moore’s law still works, and the computing power of computers is growing. This allows us to use more and more complex algorithms.
In conclusion, we note that different DI containers have different performance, and this difference can be significant (see a small study ).
This is an entry-level learning material. It will be useful for those who are not familiar with DI containers or are interested in how it is arranged from the inside.
What is it and where is it used
Dependency Injection is a common design pattern used to create programs with loosely coupled components. Beginners usually meet him on projects where unit tests are used.
A classic example of a system with tight connectivity is when a hairdryer is tightly connected to a power supply in a hotel (the owners worry about the safety of the device). The length of the wire, in general, is enough, but with this approach it is impossible to modify the hair dryer separately from the wall, and the wall - separately from the hair dryer. The introduction of loose coupling in the form of a socket and a plug solves this problem.
Another example is the tight binding of employees to the workplace, and also the need to go to work every day. This tight connection in modern companies is increasingly weakened by both the ability to work from home and the introduction of the practice of lack of a permanent workplace: if you want to come to the office - do not forget to pop a place. From the point of view of the employer, the work will be performed regardless of the seat of the employee. Of course, additional risks arise, but such is the price of greater flexibility.
The idea of implementing dependencies in the narrow sense is that the consumer class of a certain function does not access the provider class directly, by creating an instance of it, but indirectly, by reference of a certain interface type. The provider class is only required to conform to the specified interface.

Unlike the service locator, here the classes not only do not know anything about each other, but also do not contain access to the intermediary class (service locator).
In order to match a particular class (or class instance) to an interface, the so-called DI container is often used, in which the interface and implementation relationships are registered in advance. For languages that do not support reflections, that is, do not allow to operate on type properties, you can restrict yourself to a template such as composition root (consideration of this template is outside the scope of this article).
This approach provides flexibility: you can always use another, instead of one implementation of the interface, according to the circumstances.
The natural way to pass references to the consumer class is to specify them in the parameters of its constructor. As a rule, a DI container, upon request of the required interface, automatically runs through the list of parameters and recursively satisfies all the dependencies.
Another way is to pass links through properties, which is called Property Injection. To satisfy the links, the DI container goes over the list of properties and assigns the necessary links to those that meet certain criteria.
There is also a rarer method - Method Injection, where links are passed through a special method (for example, Init () listing the dependencies in the form of parameters). This approach is similar to constructor injection, but it works after creating an instance of the object. This term also means something completely different, namely the simple transfer of dependencies as parameters to an arbitrary method.
Is this another bike
There are many DI containers (e.g. Unity, NInject, Autofac, Spring, Castle Windsor, TinyIoc, MvvmCross). Most of them support Property Injection.
But sometimes there are situations when, for one reason or another, a third-party DI container is not suitable for you, and you have to write your own.
For example, corporate policies prohibit the use of third-party libraries. Or the libraries you need do not exist in nature. Or these libraries do not meet design requirements.
In this case, it is not difficult to make your own container - unless, of course, it is technically possible within the framework of the applied development technology, as is possible in .Net.
Why constructor injection does not suit
Dependency injection through constructor parameters requires creating utility variables in the consumer class, in which references from constructor parameters are stored. This is a routine operation, which, in a good way, could be somehow automated. But while there is no such automation, the programmer has to do this work. Each new dependency is added first to the constructor parameters, then to the service variables, then in the constructor a line of assignment of one to another is added.
It is often possible to observe how any of the added parameters is stretched through the code, from the top-level class to the final consumer down the inheritance hierarchy. The chain of calls stretches like a bunch of sausages, from constructor to constructor. Not only is the serial transmission of these parameters in itself cluttering up the code. So also the addition of the next parameter at the end of this chain of calls requires its modification throughout. Which is completely inconvenient. As a result, the class can solidly “swell” only because of all this machinery, without even starting to do anything.
Why not save the programmer from this routine and delegate the creation of entities to a DI container?
It can also be noted that when passing parameters to the constructor, they are usually passed without specifying the parameter name. That is, the user of the class is forced to rely either on the serial number of the parameter, or explicitly indicate the parameter name, which will further clutter up the code.
There is a good rule that if it becomes inconvenient for you to add another dependency to the constructor parameters, then it means that there really are too many of them, and you should review the design. Usually this is 5 pieces - the natural limit of objects that a person without training can hold in his area of attention.
However, we believe that the key word in this rule is inconvenient. I would like to avoid it.
Own DI container
The implementation of the simplest DI container is easy to find in the source. The author once used a small example from Xamarin University (see here ).
Much is lacking here compared to industrial DI containers (singletones, domains, etc.), but this is beyond the scope of this article.
The container allows you to register the relationship between the interface and the implementation (the Register method in different versions, which simply adds an element to the Dictionary), then, in the Resolve method, create an instance of the class that corresponds to the requested interface and do the same parameters of its constructor.
This container works on the basis of Reflections and the method Activator.CreateInstance (). The last method is used to create an instance of a class by its type, and reflections allow you to subtract type properties.
To implement property injection, we will add a special attribute with which we will mark those properties that the container should process as dependencies.
Name the attribute “ResolveAttribute”. To do this, create a System.Attribute descendant class (see Appendix A).
Add attribute processing in the Resolve method of the container.
public object Resolve(Type type)
{
object result = null;
...
//Inject [Resolve] marked properties
var props = targetType.GetRuntimeProperties()
.Where(x => x.CanWrite && x.IsDefined(typeof(ResolveAttribute)));
foreach (var item in props)
{
item.SetValue(result, Resolve(item.PropertyType));
}
return result;
}
This is all that needs to be done in the source container in order for dependency injection through properties to work (for the sources, see Appendix B).
Usage example
Suppose there is a class in which it is used to inject dependencies through the constructor (of course, dependencies must be registered in advance - see Appendix C). Note that the parameters and constructor body are purely serving code:
public class MediaRecorder : IMediaRecorder
{
private readonly IMediaPlayer player;
private readonly IRestServiceClient restClient;
private readonly ILog log;
private readonly IFileService fileService;
private readonly ISettingsProvider settingsProvider;
public MediaRecorder(IMediaPlayer player, IRestServiceClient restClient, ILog log, IFileService fileService, ISettingsProvider settingsProvider)
{
this.player = player;
this.restClient = restClient;
this.log = log;
this.fileService = fileService;
this.settingsProvider = settingsProvider;
}
}
We modify the class using the implementation through the properties:
public class MediaRecorder : IMediaRecorder
{
[Resolve]
public IMediaPlayer Player { get; set; }
[Resolve]
public IRestServiceClient RestClient { get; set; }
[Resolve]
public ILog Log { get; set; }
[Resolve]
public IFileService FileService { get; set; }
[Resolve]
public ISettingsProvider SettingsProvider { get; set; }
public MediaRecorder()
{
}
}
As you can see, the amount of utility code has decreased, and the code itself has become more readable.
The flip side to success is the reduced ability to control the integrity of the program by the compiler. However, this is a common consequence for all types of IoC implementations.
It should also be borne in mind that it is considered normal practice to use constructor injection for mandatory dependencies, and property injection for optional ones. That is why the properties in our example have a public access modifier.
Public access to dependencies makes it possible to replace their values from the outside, which, on the one hand, serves as a tool for introducing dependencies manually, and on the other hand, it allows you to inadvertently damage the work of the entire class if it is not written correctly enough.
The code in our implementation does not check the access level of the property, that is, you can use either “public” or “private”. The latter is recommended for those properties whose arbitrary modification is undesirable. This will protect the class from inadvertent misuse and, at the same time, allow the use of property injection.
Performance
As you can see from our implementation, to support Property Injection, you need to go through all the properties of the class using reflections. It may turn out that there are a lot of properties - in practice, there are more than a thousand, which somewhat slows down the program.
For this reason, this approach is not very suitable for classes with a large number of properties. Here optimization is possible both from the user code and from the container itself.
For example, it would be possible to shorten the list of properties by putting in the service class those that are not marked “ResolveAttribute” (in our implementation), think about deferred reading (lazy loading). And the container could cache the list of properties for implementation. But we'll talk about this some other time.
At the same time, Moore’s law still works, and the computing power of computers is growing. This allows us to use more and more complex algorithms.
In conclusion, we note that different DI containers have different performance, and this difference can be significant (see a small study ).
Appendix A
using System;
namespace Bricks
{
[AttributeUsage(AttributeTargets.All)]
public sealed class ResolveAttribute : Attribute
{
}
}
Appendix B
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Bricks
{
///
/// This is a very simple example of a DI/IoC container.
///
public sealed class DependencyContainer : IDependencyContainer
{
readonly Dictionary> registeredCreators = new Dictionary>();
readonly Dictionary> registeredSingletonCreators = new Dictionary>();
readonly Dictionary registeredSingletons = new Dictionary();
object locker = new object();
///
/// Register a type with the container. This is only necessary if the
/// type has a non-default constructor or needs to be customized in some fashion.
///
/// Abstraction type
/// Type to create
public void Register()
where TImpl : new()
{
registeredCreators.Add(typeof(TAbstraction), () => new TImpl());
}
///
/// Register a type with the container. This is only necessary if the
/// type has a non-default constructor or needs to be customized in some fashion.
///
/// Function to create the given type.
/// Type to create
public void Register(Func