How to build a lightweight DI (dependency injection) and di Injection
Concept: dependency injection is similar to the factory mode in IOC mode. It is a mode that solves the dependency coupling between callers and callers. It solves the dependency between objects, so that the object only depends on the IOC/DI container and does not directly depend on each other. This achieves loose coupling. Then, when the object is created, the IOC/DI container injects the dependent object into its body, therefore, it is also called the dependency injection mode to maximize loose coupling;
So what is dependency? The following code:
1 public class A{2 private B b;3 public A(B b){4 this.b = b;5 }6 public void mymethod(){7 b.m();8 }9 }
The following code indicates that A depends on B, because A's method behavior is dependent on m Implementation of B.
Container information:
1 /// <summary> 2 // configuration item in dependency injection (injection container) 3 /// </summary> 4 public class MapItem: {5 6 private Boolean _ singleton = true; 7 private Dictionary <String, String> _ maps = new Dictionary <String, String> (); 8 9 /// <summary> 10 // when the container creates an object, whether to return 11 // </summary> 12 public Boolean Singleton {13 get {return _ singleton;} 14 set {_ singleton = value;} in Singleton Mode ;} 15} 16 17 /// <summary> 18 // map19 of the object dependency injection relationship /// </s Ummary> 20 public Dictionary <String, String> Map {21 get {return _ maps;} 22 set {_ maps = value ;} 23} 24 25 /// <summary> 26 // typeFullName27 of the object /// </summary> 28 public String Type {get; set ;} 29 30 /// <summary> 31 32 // Add the injection link 33 34 /// </summary> 35 36 /// <param name = "propertyName"> attribute name </param> 37 38 // <param name = "item"> inject container </param> 39 internal void AddMap (String propertyName, mapItem) {40 AddMap (propertyName, item. name ); 41} 42 43 // <summary> 44 45 // inject 46 47 // </summary> 48 49 // <param name = "propertyName"> attribute name </param> 50 51 // <param name = "injectBy"> Object name </param> 52 internal void AddMap (String propertyName, string injectBy) {53 this. map. add (propertyName, injectBy); 54} 55 56 57 private Object _ obj; 58 59 // <summary> 60 61 // target object 62 63 // </summary> 64 [NotSave] 65 int Ernal Object TargetObject {66 get {return _ obj;} 67 set {_ obj = value;} 68} 69 70 private Type _ type; 71 72 // <summary> 73 74 // target Type 75 76 // </summary> 77 [NotSave] 78 internal Type TargetType {79 get {80 81 if (_ type! = Null) return _ type; 82 if (TargetObject! = Null) return TargetObject. GetType (); 83 return null; 84} 85 set {_ type = value;} 86} 87 88}
To use this container, we generally need to call the following external methods:
/// <Summary> /// create an Ioc-processed object. The result is not a singleton. /// Check whether injection is required. /// </Summary> /// <typeparam name = "T"> </typeparam> /// <returns> </returns> public static T Create <T> () {return (T) CreateObject (typeof (T), null) ;}/// <summary> // create an Ioc-processed object. The result is not a singleton. /// Check whether injection is required. /// </Summary> /// <param name = "targetType"> </param> /// <param name = "invokerName"> if it is automatically assembled Based on the interface, </param> // <returns> </returns> private static Object CreateObject (Type targetType, Object invoker) {if (targetType = null) return null; if (targetType. isInterface) {// interface return CreateByInterface (targetType, invoker);} // here we use AOP to construct an Object. For details, refer to the previous blog Object objTarget = AopContext. createObjectBySub (targe TType); // Inject (objTarget) into IOC; return objTarget;} // <summary> // configure IOC according to the container ), inject the dependency into the created Object // </summary> /// <param name = "obj"> </param> public static void Inject (Object obj) {if (obj = null) return; Type t = obj. getType (); MapItem mapItem = getMapItemByType (t); if (mapItem = null) {mapItem = new MapItem (); mapItem. targetType = t; mapItem. targetObject = obj;} createInstanceAndInjec T (mapItem, obj );} /// <summary> /// search for DI container by type /// </summary> /// <param name = "t"> </param> // <returns> </returns> private static MapItem getMapItemByType (Type t) {Dictionary <String, MapItem> resolvedMap = Instance. resolvedMap; // container foreach (KeyValuePair <String, MapItem> entry in resolvedMap) {MapItem item = entry. value; if (t. fullName. equals (item. type) return item;} return null ;}/// <Summary> // IOC injection: checks the attributes of an object and injects the object according to the configuration. If no configuration exists, then it is automatically assembled /// </summary> /// <param name = "mapItem"> </param> /// <returns> </returns> private static Object createInstanceAndInject (mapItem mapItem, object objTarget) {Type targetType = mapItem. targetType; if (targetType. isAbstract) {logger. info ("type is abstract =>" + targetType. fullName); return null;} if (objTarget = null) {objTarget = rft. getInstance (ta RgetType); // create an object based on reflection} // check all properties PropertyInfo [] properties = targetType. getProperties (BindingFlags. public | BindingFlags. instance); foreach (PropertyInfo p in properties) {if (! P. CanRead) continue; if (! P. CanWrite) continue; // skip if (! P. PropertyType. IsInterface) continue; // perform the injection check on the Interface // future // if there is an injection configuration Object mapValue = getMapValue (mapItem. Map, p); if (mapValue! = Null) {p. setValue (objTarget, mapValue, null);} // if no else {Object propertyValue = p. getValue (objTarget, null); // automatically assemble if (propertyValue = null) {logger. info ("property =>" + targetType. name + ". "+ p. name); propertyValue = getAutoWiredValue (p. propertyType); if (propertyValue! = Null) {p. setValue (objTarget, propertyValue, null);} else {logger. info ("property is null =>" + p. name) ;}}} return objTarget ;}
Automatic Assembly if container check does not exist
// IOC injection: Check the Object attributes. Inject the Object according to the configuration. If no configuration is configured, the private static Object createInstanceAndInject (MapItem mapItem) {return createInstanceAndInject (mapItem, null) is automatically assembled );} /// <summary> /// check whether attribute information exists in the ing relationship. // </summary> /// <param name = "maps"> </param>/ // <param name = "p"> </param> // <returns> </returns> private static Object getMapValue (Dictionary <String, string> maps, PropertyInfo p) {if (maps = null | maps. count = 0) return null; foreach (KeyValuePair <String, String> entry in maps) {Object x = GetByName (entry. Value); if (x! = Null) return x;} return null;} // <summary> // obtain the object based on the name in the configuration file of dependency injection. Singleton determines whether to use a Singleton instance based on the configuration attribute. /// </Summary> /// <param name = "objectName"> </param> /// <returns> </returns> public static Object GetByName (String objectName) {if (Instance. resolvedMap. containsKey (objectName) = false) return null; MapItem item = Instance. resolvedMap [objectName]; if (item = null) return null; if (item. singleton) return Instance. objectsByName [objectName]; else return createInstanceAndInject (item );}
Automatically bind objects based on interfaces
// Obtain the automatically bound private static Object getAutoWiredValue (Type interfaceType) {List <Type> typeList = GetTypeListByInterface (interfaceType); if (typeList. count = 0) {return null; // return null} else if (typeList. count = 1) {return Create (typeList [0], interfaceType);} else {StringBuilder msg = new StringBuilder (); foreach (Type t in typeList) {msg. append (t. fullName + ",");} throw new Exception (s Tring. Format ("there are multiple interface implementations. The interface = {0}, implementation = {1} is not explicitly specified and cannot be automatically injected. ", InterfaceType. fullName, msg) ;}}// obtain the instance public static List <Type> GetTypeListByInterface (Type interfaceType) {List <Type> typeList = new List <Type> () based on the interface (); foreach (KeyValuePair <String, Type> kv in Instance. typeList) {if (rft. isInterface (kv. value, interfaceType) {typeList. add (kv. value) ;}} return typeList ;}