In the first two implementations, many of the internal details are not known, Microsoft's Framework is to block the implementation, only let us focus on the interface. But people are full of curiosity, how does dependency injection come true?
What kind of implementation does Microsoft have? Here's a show for everyone (honestly, the code is really hard to read)
First look at the core class:servicetable
Internal classservicetable {Private ReadOnly Object_sync =New Object(); Private ReadOnlyDictionary<type, serviceentry>_services; Private ReadOnlyDictionary<type, list<igenericservice>>_genericservices; Private ReadOnlyConcurrentdictionary<type, Func<serviceprovider,Object>> _realizedservices =NewConcurrentdictionary<type, Func<serviceprovider,Object>>(); PublicServicetable (ienumerable<servicedescriptor>descriptors) {_services=NewDictionary<type, serviceentry>(); _genericservices=NewDictionary<type, list<igenericservice>>(); foreach(varDescriptorinchdescriptors) { varServicetypeinfo =Descriptor. Servicetype.gettypeinfo (); if(servicetypeinfo.isgenerictypedefinition) {ADD (descriptor. ServiceType,NewGenericservice (descriptor)); } Else if(Descriptor. Implementationinstance! =NULL) {ADD (descriptor. ServiceType,NewInstanceservice (descriptor)); } Else if(Descriptor. Implementationfactory! =NULL) {ADD (descriptor. ServiceType,NewFactoryservice (descriptor)); } Else{ADD (descriptor. ServiceType,NewService (descriptor)); } } } PublicConcurrentdictionary<type, Func<serviceprovider,Object>>realizedservices {Get{return_realizedservices;} } Public BOOLTrygetentry (Type servicetype, outServiceentry Entry) { Lock(_sync) {if(_services. TryGetValue (ServiceType, outentry)) { return true; } Else if(Servicetype.gettypeinfo (). Isgenerictype) {varOpenservicetype =servicetype.getgenerictypedefinition (); List<IGenericService>Genericentry; if(_genericservices.trygetvalue (Openservicetype, outgenericentry)) { foreach(varGenericserviceinchgenericentry) { varClosedservice =Genericservice.getservice (servicetype); if(Closedservice! =NULL) {Add (servicetype, Closedservice); } } return_services. TryGetValue (ServiceType, outentry); } } } return false; } Public voidAdd (Type servicetype, IService service) {Lock(_sync) {Serviceentry entry; if(_services. TryGetValue (ServiceType, outentry)) {entry. ADD (service); } Else{_services[servicetype]=Newserviceentry (service); } } } Public voidAdd (Type servicetype, Igenericservice genericservice) {Lock(_sync) {List<IGenericService>Genericentry; if(!_genericservices.trygetvalue (ServiceType, outgenericentry)) {Genericentry=NewList<igenericservice>(); _genericservices[servicetype]=Genericentry; } genericentry.add (Genericservice); } } }
View Code
First look at the properties of the code:
Private ReadOnly Dictionary<type, serviceentry> _services; Private ReadOnly Dictionary<type, list<igenericservice>> _genericservices; Private ReadOnly Object New Object>> ();
The Serviceentry class, as described later, can be used as a class that produces an object. So "_services" is the dictionary that holds the correspondence between the type and the instance.
"_genericservices", as the name implies, is definitely related to generics, in fact "_genericservices" type is similar to "list<t>" this kind contains generic definition types.
The last _realizedservices definition is more complex. May not understand what it means. Actually also defines a dictionary table (concurrentdictionary), and unlike dictionary, multithreading support is better. The first generic argument of the dictionary table is type, and the second parameter is a Func proxy, and the Func proxy (which can be used by Baidu C#+func query for detailed usage) is serviceprovider, and the return value is object.
[ When an injection gets an instance, it queries whether _realizedservices already contains the instance, if there is a query, if none is produced in _services, then adds the resulting result to realizedservices and returns; Services also does not have, then the generic type "argument session" is _genericservices, all types matching are added to the _services, and then obtained from _services ]
From the constructor of the class, it can be found that the IService (Igenericservice) order based on the Servicedescriptor object is:genericservice->instanceservice-> Factoryservice->service (and AUTOFAC, Ninject are different).
Interface Definition: Igenericservice, IService, Iservicecallsite
Internal Interface Igenericservice { get;} IService GetService (Type closedservicetype); }
Internal Interface IService { getset;} Get ; } Iservicecallsite Createcallsite (serviceprovider provider, ISet<Type> callsitechain); }
Internal Interface Iservicecallsite { object Invoke (serviceprovider provider); Expression Build (expression provider); }
Iservicecallsite interface: Similar to a factory class, the ability to generate object objects through an invoke call, that is, the last object generated by the dependency injection is the responsibility of the instance of the interface.
IService interface: Lifetime life cycle, Createcallsite creates iservicecallsite through ServiceProvider, which is the ability to indirectly create instance objects. I think the next attribute is not too appropriate to put in the interface, and the next object references itself, making the iservice have a chain structure.
Igenericservice interface: Generates a IService interface.
[ Here's a question to think about, Igenericservice and IService are designed to be easy to understand, and the generics and non-generic gaps are large enough to not share an interface.] But why can't the IService interface and the Iservicecallsite interface be merged into one interface? The interface definition is as follows:
Internal Interface IService { get;} Object Invoke (serviceprovider provider); }
]
Serviceentry class
Internal classServiceentry {Private Object_sync =New Object(); Publicserviceentry (IService service) { First=Service; Last=Service; } PublicIService First {Get;Private Set; } PublicIService last {Get;Private Set; } Public voidAdd (IService service) {Lock(_sync) {Last.next=Service; Last=Service; } } }
Serviceentry
The Serviceentry class is relatively simple. is equivalent to a iservice one-way list, which then contains the starting node of the list and the end node. The Add method allows the new node to be added to the end of the list.
[ Best of all, why not use linklist this list structure, or write a list of generic classes, add self-references within IService, always feel not a good design ]
Looking back, we look at servicetable 's dictionary<type, serviceentry> _services property, is actually a type, registered a lot of IService interface , and these interfaces are stored in list order.
Look back at servicetable .
The two add methods are simple to determine if the list/array of type types exists, and if so, the Add method of the call list/array does not exist to create one.
More interesting is the Tryget method, first in the non-generic search, if not present, then to the generic search. and the generic "argument". This piece of code deserves our deep research.
Public BOOLTrygetentry (Type servicetype, outServiceentry Entry) { Lock(_sync) {if(_services. TryGetValue (ServiceType, outentry)) { return true; } Else if(Servicetype.gettypeinfo (). Isgenerictype) {varOpenservicetype =servicetype.getgenerictypedefinition (); List<IGenericService>Genericentry; if(_genericservices.trygetvalue (Openservicetype, outgenericentry)) { foreach(varGenericserviceinchgenericentry) { varClosedservice =Genericservice.getservice (servicetype); if(Closedservice! =NULL) {Add (servicetype, Closedservice); } } return_services. TryGetValue (ServiceType, outentry); } } } return false; }
Trygetentry
[servicetable 's two properties Dictionary<type, serviceentry> _services and Dictionary<type, List<igenericservice>> _genericservices These two attributes are one-way lists, one using list, neat friends will feel very uncomfortable there is no, there is no. Why can't we all be united and let us be comfortable? ]
[ASP. 5] Dependencyinjection Project Code Analysis 4-Implementation of Microsoft (on)