Unity is a lightweight and scalable dependency injection container developed by the Microsoft patterns & Practices Team. It supports three common dependency injection methods: constructor injection, property injection, and method call injection ). now the latest version of Unity 1.2 can be found inMicrosoft Open Source site http://unity.codeplex.comDownload the latest release version and documentation. By using unity, we can easily build programs with loosely coupled structures, making the entire program framework clear and easy to maintain.
In the normal software coding process, the logic of the program is often very complicated. Especially in the development of large projects, a module often references other modules. Suppose we have a monitor class, it is used to monitor the CPU temperature. When the temperature reaches the warning range, the monitor has an alarm method, which sends a text message to the maintenance personnel by sending a text message. The following code is the most common one:
1: public class Monitor
2: {
3: public void Alarm()
4: {
5: SMSNotify notify = new SMSNotify();
6: notify.Send();
7: }
8: }
The monitor class directly references a text message wake-up class, which is the most inflexible and not easy to expand. Maybe we think of interface-oriented programming. Using the benefits of polymorphism, we can provide flexible implementations of different subclasses and increase code scalability. But in the end, the interface must be implemented, that is, the following statement will be executed sooner or later:
1: public void Alarm()
2: {
3: INotify notify = new SMSNotify();
4: notify.Send();
5: }
In this case, the inotify interface still needs to be implemented by specific classes, and such code is fixed during program compilation, if you need to use a new daemon later, you still need to modify the source code and re-compile it. In our monitor class, we obviously rely on the smsnoodle class, and the coupling between them is very close. Therefore, the IOC (control inversion) mode is proposed to solve this problem, that is, to delay the specific implementation of the interface to the runtime, the implementation class of the interface is loaded at the runtime. In this way, even with a new implementation class, you do not need to change the caller's code (you can use the configuration file in Unity ). This IoC pattern can be illustrated as an image: an interface is like an empty shell, and content is injected into this shell in actual implementation, making it a real entity. This mode is also known as dependency injection. By using unity, we can build loosely coupled software, and we don't have to worry about the details of the associations between objects. We can leave the dependency injection container with full responsibility.
We also mentioned three common forms of dependency injection: constructor injection, property injection, and method call injection. We can use examples to implement these three forms of injection. Take the preceding scenario as an example:
1. constructor Injection
IMonitor interface definition:
1: public interface IMonitor
2: {
3: void Alarm();
4: }
Monitor class:
1: public class Monitor : IMonitor
2: {
3: private INotify notify;
4:
5: public Monitor(INotify n)
6: {
7: notify = n;
8: }
9:
10: public void Alarm()
11: {
12: notify.Send();
13: }
14: }
Inotify interface definition:
1: public interface INotify
2: {
3: void Send();
4: }
Emailpolicy class:
1: public class EmailNotify : INotify
2: {
3: public void Send()
4: {
5: Console.WriteLine("Send Email Notify...");
6: }
7: }
Smsnoodle class:
1: public class SMSNotify : INotify
2: {
3: public void Send()
4: {
5: Console.WriteLine("Send SMS Notify...");
6: }
7: }
As you can see, in the constructor of the monitor class, the input parameter is an inotify interface type, alarm method, and the send method of the implementation class is called, however, the send method of which implementation class is called is only known after the object is injected. In the unity container, registertype and resolve methods are usually used to register and obtain instances respectively. These two methods have a lot of generics and non-generic overloading, specific types and parameters, refer to the official help document of unity.
Now we inject instances that implement the inotify interface to the monitor constructor:
1: static void Main(string[] args)
2: {
3: IUnityContainer container = new UnityContainer();
4: container.RegisterType<IMonitor, Monitor>().RegisterType<INotify, SMSNotify>();
5:
6: IMonitor monitor = container.Resolve<IMonitor>();
7: monitor.Alarm();
8:
9: Console.ReadLine();
10: }
In the code, the inotify instance we inject is an instance of the smsnoop class, and then the monitor. alrarm () is called, which calls notify. Send ().
The above is for a single constructor. If there are multiple constructor, You need to specify which constructor needs to be injected, that is, you need to add attribute to the specified constructor: injectionconstructor
1: public Monitor(INotify n, string name)
2: {
3: notify = n;
4: }
5:
6: [InjectionConstructor]
7: public Monitor(INotify n)
8: {
9: notify = n;
10: }
You can get the same result after running.
2. Property Injection
Through Property injection, we need to add attribute: dependency so that the unity container will automatically instantiate the object that the property depends on when obtaining the class object instance and inject it into the property.
Modify the monitor class to implement the following code:
1: public class Monitor : IMonitor
2: {
3: [Dependency]
4: public INotify Notify { get; set; }
5:
6: public void Alarm()
7: {
8: Notify.Send();
9: }
10: }
In the main function, modify the original code. This time, we inject the container into the emailpolicy instance:
1: container.RegisterType<INotify, EmailNotify>();
In addition, you can specify a name for the dependency feature. In this way, the entity with the corresponding name specified by registertype is injected during injection. For example:
1: public class Monitor : IMonitor
2: {
3: [Dependency("SMS")]
4: public INotify Notify { get; set; }
5:
6: public void Alarm()
7: {
8: Notify.Send();
9: }
10: }
Modify the main function and specify the injection name in the registertype function:
1: container.RegisterType<INotify, EmailNotify>("Email");
2: container.RegisterType<INotify, SMSNotify>("SMS");
3. method call Injection
The time of method call injection is different from that of constructor injection. constructor injection is used when the container creates an instance, and method call injection is used when the method is called. To implement method call injection, you must add attribute: injectionmethod before the specified injection method.
The code for modifying the monitor class is as follows:
1: public class Monitor : IMonitor
2: {
3: private INotify notify;
4:
5: [InjectionMethod]
6: public void GetNotify(INotify n)
7: {
8: notify = n;
9: }
10:
11: public void Alarm()
12: {
13: notify.Send();
14: }
15: }
When the program runs, the container will automatically instantiate the object on which the getnotify method depends, and automatically call this method to inject it into the method.
The main function is as follows:
1: static void Main(string[] args)
2: {
3: IUnityContainer container = new UnityContainer();
4: container.RegisterType<IMonitor, Monitor>();
5: container.RegisterType<INotify, EmailNotify>();
6:
7: IMonitor monitor = container.Resolve<IMonitor>();
8: monitor.Alarm();
9:
10: Console.ReadLine();
11 :}
From http://www.lywill.com/archives/kf/2013/Microsoft-Practices-UnityRuMen)