Unity IoC Container Creating object procedures

Source: Internet
Author: User
Tags list of attributes

Unity is an open-source IOC framework launched by Microsoft P&p, the latest official version is 2.0. The previous version of Unity was built on a component called Objectbuild, familiar with Enterlib's readers, believing that Objectbuild would not feel unfamiliar. For versions prior to Enterlib 5.0, Objectbuild can be said to be the cornerstone of any application block. Objectbuild provides an extensible, customizable way to create objects , although Microsoft officially does not associate Objectbuild with IOC, and its nature can be seen as an IOC framework. In Unity 2.0, Microsoft directly implemented most of the functionality of Objectbuild (actually the second version of Objectbuild ObjectBuild2) in unity, while Enterlib was built directly on unity. This shows unity's importance in Enterlib and other Microsoft open source frameworks, such as software Factory.

There were also some articles about enterlib in the garden, including the introduction of Unity/objectbuild. While Microsoft has claimed unity to be a lightweight IOC framework, it doesn't mean unity will be easy. It is precisely because of the complexity of unity/objectbuild, many people write about Unity/objectbuild, often in order to cover up, leading to a lot of readers unintelligible. The end result is that the reader who understands Unity/objectbuild is able to read or not understand. In this article, I try a different approach: seize the essence of unity/objectbuild, remove some of the minutiae, and hope to make the reader understand the essence of unity in a new perspective.

First, from the pipeline + context (Pipeline+context) mode.

If you want to say what design/architecture pattern the Unity container uses, my answer is "Pipeline + context (Pipeline + contextual) mode" (I don't know if I really have one). In the chapter on binding in WCF Technical Anatomy (Volume 1), I used to make an analogy with this pattern: "For example, there is a water plant that provides drinking water for residents, and its task is to extract the natural water source, carry out the necessary purification, and eventually deliver it to the residential area." The process of purifying treatment may be this: the natural water source is drawn into a reservoir to filter the impurities first (we call this Pool a filter); The filtered water flow is disinfected in the second pond (we call this Pool A disinfection tank) , the sterilized water flow to the third pond for water softening treatment (we call this Pool A softening pond), and eventually the water flows through the piped water to the residents ' homes. ”

When we need to create an infrastructure for a series of processing of an element (water that needs to be processed in an example), we can implement the corresponding processing logic (filtering, disinfection, and softening in the example) in the corresponding "node" (Filter pool, disinfection pool, and softening pool in the example). An orderly combination of the corresponding nodes according to needs (e.g. water quality) (different water quality determines the difference in the processing process) thus constituting a pipeline (the entire water treatment pipeline for the waterworks). Since each node has a standard interface, we can arbitrarily reorganize the nodes that make up the pipeline, or we can customize the nodes for some kind of need, so that our "pipelines" become adaptable to all processing needs.

In fact, we are not unfamiliar with this design. For example, the runtime of an ASP. NET can be seen as a pipeline of HTTP requests made up of several httpmodule, and the binding in WCF is a pipeline of message processing consisting of several channels (channel). The same design is also reflected in the design of. NET Remoting, BizTalk and other related frameworks and products.

The "node" based on the corresponding standard makes the pipeline, but how does each relative independent node cooperate? This requires sharing some context within the entire pipeline scope, which encapsulates the pipeline processing object and the processing environment. Asp. The context object of the net runtime pipeline is HttpContext, and the context of the binding pipeline is BindingContext.

Second, UnityContainer is the Buildstrategy pipeline

As an IOC framework, Unity Container's ultimate purpose is to dynamically parse and inject dependencies, ultimately providing (creating new objects or providing existing objects) an object that meets your requirements. To make the entire object delivery process extensible and customizable, the entire process is designed as a pipeline. Each node of the pipeline is called a builderstrategy, and they participate in the entire object delivery process according to their respective policies.

In addition to providing functionality for objects, Unity container provides another counter-function: Object recycling. For the moment we call both build-up and tear-down. Build-up and Tear-down use the same processing mechanism.

The diagram on the left reflects Unity container a pipeline of build-up and tear-down of objects made up of several builderstrategy. Each buildstrategy has the same interface (this interface is ibuilderstrategy) and they have four standard methods: Prebuildup, Postbuildup, Preteardown, and Postteardown. From the name we are not difficult to see, four methods are used to complete the object before/after the creation and the object before and after the corresponding operation. Specifically, when you need to use this pipeline to create an object, call the Prebuildup method in the order in which Builderstrategy is in the pipeline, and then invoke the Postbuildup method in reverse order after the bottom of the pipeline.

For each builderstrategy that makes up the Unity container pipeline, they are independent of each other, and a builderstrategy only needs to do the corresponding actions based on its own policy. No need to know the existence of other builderstrategy. Only in this way can the flexible customization of pipelines be realized, and truly scalable. But when it comes to real work, there is a need to share some context to facilitate collaboration. Here, Buildercontext played such a role. In unity, Buildercontext implements Ibuildercontext, so let's take a look at what Ibuildercontext defines:

1:public Interface Ibuildercontext
2: {
3://others ...
4:bool Buildcomplete {get; set;}
5:namedtypebuildkey Buildkey {get; set;}
6:namedtypebuildkey originalbuildkey {get;}
7:object currentoperation {get; set;}
8:object Existing {get; set;}
9:}

In the above definition of ibuildercontext, for simplicity, I deliberately omitted some attributes. In the list of attributes above, Buildcomplete indicates whether the build operation is identified as ending, and if a builderstrategy has completed the build operation, it can be set to true. This allows subsequent builderstrategy to operate accordingly (most will not be followed by build); Buildkey and Originalbuildkey are a type + Name is a combination of keys representing the current build operation (represented by Currentoperation); The existing property represents an object that has already been generated, and in general Builderstrategy assigns the object it generates to that value While the strategies represents the entire Builderstrategy pipeline.

Third, create a simplest builderstrategy

Now let's write one of the simplest examples to see how unitycontainer is providing the object with the help of the Builderstrategy pipeline (you can download the source code here). Let's start by creating the simplest builderstrategy, our strategy is to create the object by reflection, so we'll name the Builderstrategy reflectionbuilderstrategy.

1:public class Reflectionbuilderstrategy:builderstrategy
2: {
3:public override void Prebuildup (Ibuildercontext context)
4: {
5:if (context. Buildcomplete | | Null! = context. Existing)
6: {
7:return;
8:}
9:var value = activator.createinstance (context. Buildkey.type);
10:if (null! = value)
11: {
12:context. Existing = value;
13:context. Buildcomplete = true;
14:}
15:}
16:}

Reflectionbuilderstrategy inherits from the unified base class Builderstrategy. Since we only need reflectionbuildstrategy to create the object, here we just need to rewrite the Prebuildup method. In the Prebuildup method, if the object that needs to be provided already exists (judging by the existing property of Buildercontext) or the build operation is completed (judging by the Buildcomplete property of Buildercontext), is returned directly. Otherwise, the type of the object needs to be created through the Buildkey property of Buildercontext, the object is created through a reflection mechanism, assigned to the existing property of Buildercontext, and Buildcomplete is set to true.

Now that Builderstrategy has been created, how do you add it to the UnityContainer Builderstrategy pipeline? In general, we need to create the appropriate extension object for Builderstrategy. To do this, we create a type reflectioncontainerextension that inherits from Unitycontainerextension:

1:public class Reflectioncontainerextension:unitycontainerextension
2: {
3:protected override void Initialize ()
4: {
5:this. Context.Strategies.AddNew (unitybuildstage.precreation);
6:}
7:}

In Reflectioncontainerextension, I just rewrote the Initialize method. In this method, the corresponding UnityContainer Builderstrategy pipeline is obtained through the context property, and the AddNew method is called to add the reflectionbuilderstrategy we created. The generic method AddNew accepts an enumeration of type Unitybuildstage. Unitybuildstage represents a stage in the entire build process, where the added builderstrategy is positioned in the pipeline. Now let's assume we need to create the following object of type Foo through UnityContainer:

1:public class Foo
2: {
3:public Guid Id {get; private set;}
4:
5:public Foo ()
6: {
7:id = Guid.NewGuid ();
8:}
9:}

The actual delivery of the object through UnityContainer is implemented in the code below. Since UnityContainer in the process of initialization through unitydefaultstrategiesextension such an extension, so I deliberately by calling Removeallextension to clear it. Then call AddExtension to add the reflectioncontainerextension we created above to the UnityContainer extension list. The last 3 calls to UnityContainer's Resolve method get the Foo object and the ID output.

1:static void Main (string[] args)
2: {
3:iunitycontainer container = new UnityContainer ();
4:container. Removeallextensions ();
5:container. AddExtension (New Reflectioncontainerextension ());
6:console.writeline (container. Resolve (). ID);
7:console.writeline (container. Resolve (). ID);
8:console.writeline (container. Resolve (). ID);
9:}
10:}

The following is the output result:

B38aa0b4-cc69-4d16-9f8c-8ea7baf1d853ef0cefc2-ffac-4488-ad96-907fb568360b08c538df-e208-4ef9-abe0-df7841d7ab60

Iv. Implementing a singleton mode with custom Builderstrategy

The above example has been able to basically reflect the unitycontainer with the help of the Builderstrategy pipeline object to provide the mechanism. To further illustrate the existence of the "pipeline", we then customize another simple builderstrategy to implement our familiar singleton pattern (based on the UnityContainer object, which is a singleton). Here is the builderstrategy:singletonbuilderstrategy that implements the singleton pattern, and the corresponding unity extension. In Singletonbuilderstrategy, we use a static dictionary to cache the creation of a successful object, the object's key in the dictionary is the type of the object being created. The created object is cached in the PostCreate method and is returned in PreCreate. In order to use the singletonbuilderstrategy as the front end of the pipeline, the unitybuildstage specified at the time of the addition is setup.

1:public class Singletonbuilderstrategy:builderstrategy
2: {
3:private static IDictionary cachedobjects = new Dictionary ();
4:
5:public override void Prebuildup (Ibuildercontext context)
6: {
7:if (Cachedobjects.containskey) (context. Originalbuildkey.type))
8: {
9:context. Existing = Cachedobjects[context. Buildkey.type];
10:context. Buildcomplete = true;
11:}
12:}
13:
14:public override void Postbuildup (Ibuildercontext context)
15: {
16:if (Cachedobjects.containskey) (context. Originalbuildkey.type) | | NULL = = Context. Existing)
17: {
18:return;
19:}
20:
21:cachedobjects[context. Originalbuildkey.type] = context. Existing;
22:}
23:}
24:
25:public class Singletoncontainerextension:unitycontainerextension
: {27:protected override void Initialize ()
28: {
29:this. Context.Strategies.AddNew (Unitybuildstage.setup);
30:}
31:}

Now, we'll add the Singletonbuilderstrategy-based extension to the previous program. Run our program again, you will find the output ID is the same, so that three times created objects are the same.

1:class Program
2: {
3:static void Main (string[] args)
4: {
5:iunitycontainer container = new UnityContainer ();
6:container. Removeallextensions ();
7:container. AddExtension (New Reflectioncontainerextension ());
8:container. AddExtension (New Singletoncontainerextension ());
9:console.writeline (container. Resolve (). ID);
10:console.writeline (container. Resolve (). ID);
11:console.writeline (container. Resolve (). ID);
12:}
13:}

Output Result:

254e1636-56e7-42f7-ad03-493864824d42254e1636-56e7-42f7-ad03-493864824d42254e1636-56e7-42f7-ad03-493864824d42

Summary: Although Unity's specific implementation mechanism is relatively complex, its essence is the Builderstrategy+buildercontext-based pipeline+context mechanism introduced in this paper. When you study unity's specific implementation principles, grasping this principle will keep you from losing your way.

Unity IoC Container Creating object procedures

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.