
DI and IoC for beginners
The DI / IoC topic is quite simple, but it’s very difficult to find a good description of how it works and why you need it on the web. Here is my attempt using Unity. Whether the topic is well explained is up to you to judge.
Let's create a simple example:
In short, our problem is this
How? This is exactly what the IoC and DI patterns do. IoC (Inversion of Control) is a pattern in which the control of an object (in our case, the lifetime of an object) is assigned to some component. Some kind of outsourcing - instead of creating the object ourselves (through
True, each time asking for a copy of the object from the container is lazy. In these cases, we can use a different pattern. DI (Dependency Injection)allows us to automatically pull the dependencies we need from the container during initialization. That is, when we create
We will use the Unity framework for our program. To begin with, we rewrite it
That's all! Thanks for attention! If you are interested in the topic and you live in St. Petersburg, come to our meeting tomorrow .
Read Part 2 of the series
Let's create a simple example:
// сервис. содержит бизнес-логику
public class MyService
{
public MyService()
{
⋮
}
public void DoSomething()
{
⋮
}
}
// окошко. пользуется бизнес-логикой
public class MyWindow : Form
{
private MyService service;
public MyWindow()
{
service = new MyService();
}
}
// програмка которая показывает окошко
public class MyProgram
{
static void Main()
{
⋮
/// создаем окно
Application.Run(new MyWindow);
}
}
There is one problem in this code: the class is MyWindow
too attached to the class MyService
. This is bad because- It will not work to write a unit test for
MyWindow
in isolation fromMyService
. In fact, we get an integration test. - It is impossible to replace
MyService
withOtherService
, unlessOtherService
it inherits from it. IfMyService
several classes depend on you, you will have to change them all. - If our service requires configuration, it will have to be configured in each class that uses it.
In short, our problem is this
operator new()
. In order to competently control dependencies and allow yourself to test objects in isolation, you need to refuse this operator. How? This is exactly what the IoC and DI patterns do. IoC (Inversion of Control) is a pattern in which the control of an object (in our case, the lifetime of an object) is assigned to some component. Some kind of outsourcing - instead of creating the object ourselves (through
new()
), we request it from the so-called IoC-container, that is, a factory that can competently produce objects. True, each time asking for a copy of the object from the container is lazy. In these cases, we can use a different pattern. DI (Dependency Injection)allows us to automatically pull the dependencies we need from the container during initialization. That is, when we create
MyWindow
through the IoC container, the DI mechanism can magically initialize MyService
without our direct participation.How it works?
We will use the Unity framework for our program. To begin with, we rewrite it
Main()
- create a container in it and apply DI to our window:public class MyProgram
{
static void Main()
{
⋮
var uc = new UnityContainer();
Application.Run(uc.Resolve() );
}
}
By the Resolve()
container method , we request not only the creation of an object of the type MyWindow
, but also the automatic creation of all its dependencies . Now let's look at how you can get the creation of a service (i.e. the dependent part) automatically. First, pull out the service interface so that you can change it later:interface IService
{
void DoSomething();
}
public class MyService : IService
{
⋮ // все как и раньше
}
Now we change MyWindow
so that the interface is used. There are several options for how you can add a link to a service so that the container initializes it. Here is one of them:public class MyWindow : Form
{
private IService service;
public MyWindow(IService service)
{
this.service = service;
}
}
Now it remains to do only one thing - to tell the container so that at the request of objects of the type IService
it produces MyService
:public class MyProgram
{
static void Main()
{
⋮
var uc = new UnityContainer();
uc.RegisterType();
Application.Run(uc.Resolve());
}
}
That's all!!! Now, when the program starts, the variable service
window will be initialized automatically . This is called constructor injection. Want to leave the constructor empty? You are welcome:public class MyWindow : Form
{
[Dependency]
public IService Service { get; set; }
public MyWindow()
{
⋮
}
}
Changing the field to a property and marking it with an attribute [Dependency]
, we hinted to the container that it needs to be initialized when creating the class. The result is the same as with the constructor. This technique is called “setter injection”. That's all! Thanks for attention! If you are interested in the topic and you live in St. Petersburg, come to our meeting tomorrow .
Read Part 2 of the series