Other Posts in Data Types

  1. Replacing List
  2. Factory Pattern using Generics in C#
  3. Vector Class and Events in .Net
  4. Binary Trees in C# using Generics
  5. Priority Queue in C#
  6. Cheap Trick for Fluent Interfaces
  7. Building an DI Container

Building an DI Container

11/13/2011

It has been a while since I've written anything. To say the least things are hectic.  Most of which, I can't really talk about at this point (let's just say that I'm working on a product for a sector of the business world. I think I can say that much, but not much more until it gets closer to release). Anyway, today I'm finally getting around to talking about one more item that I've added to my utility library. Specifically I've added a basic DI container (dependency injection).

Note that this next section is an over simplification and I'm tired so if it's wrong, feel free to say so. Anyway, Dependency injection is a specific form of inversion of control. Inversion of control is when you invert the flow of a system. Instead of one central bit of code deciding how everything is run, it's up to the individual pieces to know how to do the actual work. For instance, if I call an object factory to create a database connection for me, I don't care how it's created or how the connection is doing anything as long as it gets done. And dependency injection is just a specific form of IoC. Instead of hard coding our dependencies in each individual class, we allow someone to pass in the component that they want to use. You can actually do this manually (using a factory pattern, etc.) and still have a form of dependency injection. However you can also automate this process using one of the many dependency injectors out there (I personally like Ninject and based the code below on it). But where's the fun in using someone else's when all we have to do is spend an afternoon and build our own.

   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using Utilities.IoC.Providers;
  28: using Utilities.IoC.Mappings;
  29: using Utilities.IoC.Mappings.Interfaces;
  30: using System.Reflection;
  31: using System.IO;
  32: using Utilities.IO.ExtensionMethods;
  33: using Utilities.Reflection.ExtensionMethods;
  34: using Utilities.DataTypes.ExtensionMethods;
  35: #endregion
  36:  
  37: namespace Utilities.IoC
  38: {
  39:     /// <summary>
  40:     /// Manager class
  41:     /// </summary>
  42:     public class Manager
  43:     {
  44:         #region Constructor
  45:  
  46:         /// <summary>
  47:         /// Constructor
  48:         /// </summary>
  49:         public Manager()
  50:         {
  51:             if (ProviderManager.IsNull())
  52:                 ProviderManager = new ProviderManager();
  53:             if (MappingManager.IsNull())
  54:                 MappingManager = new MappingManager(ProviderManager);
  55:         }
  56:  
  57:         #endregion
  58:  
  59:         #region Functions
  60:  
  61:         /// <summary>
  62:         /// Loads all mapping modules found within the assembly
  63:         /// </summary>
  64:         /// <param name="ModuleAssembly">Module assembly</param>
  65:         public void Setup(Assembly ModuleAssembly)
  66:         {
  67:             ProviderManager.Setup(ModuleAssembly);
  68:             MappingManager.Setup(ModuleAssembly);
  69:         }
  70:  
  71:         /// <summary>
  72:         /// Loads all mapping modules found within the assemblies
  73:         /// </summary>
  74:         /// <param name="ModuleAssemblies">Module assemblies</param>
  75:         public void Setup(IEnumerable<Assembly> ModuleAssemblies)
  76:         {
  77:             ModuleAssemblies.ForEach(x => Setup(x));
  78:         }
  79:  
  80:         /// <summary>
  81:         /// Loads all mapping modules found within a specific directory
  82:         /// </summary>
  83:         /// <param name="Directory">Directory to scan for modules</param>
  84:         /// <param name="RecursiveScan">Determines if sub directories should be scanned</param>
  85:         public void Setup(string Directory, bool ScanSubDirectories = true)
  86:         {
  87:             Setup(new DirectoryInfo(Directory).LoadAssemblies(ScanSubDirectories));
  88:         }
  89:  
  90:         /// <summary>
  91:         /// Creates an object of the specified type
  92:         /// </summary>
  93:         /// <typeparam name="ServiceType">Service type</typeparam>
  94:         /// <returns>An object of the specified type</returns>
  95:         public ServiceType Get<ServiceType>()
  96:         {
  97:             return (ServiceType)Get(typeof(ServiceType));
  98:         }
  99:  
 100:         /// <summary>
 101:         /// Creates an object of the specified type associated with the attribute type
 102:         /// </summary>
 103:         /// <typeparam name="ServiceType">Service type</typeparam>
 104:         /// <typeparam name="AttributeType">Attribute type</typeparam>
 105:         /// <returns>An object of the specified type</returns>
 106:         public ServiceType Get<ServiceType, AttributeType>()
 107:         {
 108:             return (ServiceType)Get(typeof(ServiceType), typeof(AttributeType));
 109:         }
 110:  
 111:         /// <summary>
 112:         /// Creates an object of the specified type
 113:         /// </summary>
 114:         /// <param name="ServiceType">Service type</param>
 115:         /// <returns>An object of the specified type</returns>
 116:         public object Get(Type ServiceType)
 117:         {
 118:             IMapping Mapping = MappingManager.GetMapping(ServiceType);
 119:             if (Mapping.IsNull())
 120:                 throw new ArgumentException("ServiceType not found in mappings");
 121:             return Mapping.Implementation.Create();
 122:         }
 123:  
 124:         /// <summary>
 125:         /// Creates an object of the specified type associated with the attribute type
 126:         /// </summary>
 127:         /// <param name="ServiceType">Service type</param>
 128:         /// <param name="AttributeType">Attribute type</param>
 129:         /// <returns>An object of the specified type</returns>
 130:         public object Get(Type ServiceType, Type AttributeType)
 131:         {
 132:             IMapping Mapping = MappingManager.GetMapping(ServiceType, AttributeType);
 133:             if (Mapping.IsNull())
 134:                 throw new ArgumentException("ServiceType not found in mappings");
 135:             return Mapping.Implementation.Create();
 136:         }
 137:  
 138:         #endregion
 139:  
 140:         #region Properties
 141:  
 142:         protected static ProviderManager ProviderManager { get; set; }
 143:         protected static MappingManager MappingManager { get; set; }
 144:  
 145:         #endregion
 146:     }
 147: }

This is our main point of code that we are going to use to get our objects. We set it up, call Get, and it will return to us our object (with the appropriate items injected). One thing that you'll notice is that there are a couple nonstandard C# calls in there (specifically the ForEach on the IEnumerable, IsNull, etc). These are all functions from the new utility library that I'm working on. I've been adding quite a bit to it, tons of extension methods, etc. So go and check out the repository as all of my code on here uses it (or at least the code on here uses a version of it). Plus any updates to the code can be found there also as I tend to forget the pages on this site. Anyway another thing you may notice is there isn't much code here. Most of the actual work is going to be done in the ProviderManager and MappingManager.

   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using Utilities.IoC.Providers.Interfaces;
  28: using Utilities.IoC.Providers.Scope;
  29: using Utilities.Reflection;
  30: using Utilities.Reflection.ExtensionMethods;
  31: using Utilities.DataTypes.ExtensionMethods;
  32: using System.Reflection;
  33: #endregion
  34:  
  35: namespace Utilities.IoC.Providers
  36: {
  37:     /// <summary>
  38:     /// Provider manager
  39:     /// </summary>
  40:     public class ProviderManager
  41:     {
  42:         #region Constructor
  43:  
  44:         /// <summary>
  45:         /// Constructor
  46:         /// </summary>
  47:         public ProviderManager()
  48:         {
  49:             Providers = new List<IProvider>();
  50:             Providers.AddRange(typeof(ProviderManager).Assembly.GetObjects<IProvider>());
  51:         }
  52:  
  53:         #endregion
  54:  
  55:         #region Functions
  56:  
  57:         /// <summary>
  58:         /// Sets up all providers found within the assembly specified
  59:         /// </summary>
  60:         /// <param name="Assembly">Assembly to scan</param>
  61:         public void Setup(Assembly Assembly)
  62:         {
  63:             Providers.AddRange(Assembly.GetObjects<IProvider>());
  64:         }
  65:  
  66:         /// <summary>
  67:         /// Gets the specified provider based on the scope specified
  68:         /// </summary>
  69:         /// <param name="Scope">Scope</param>
  70:         /// <returns>The specified provider</returns>
  71:         public IProvider GetProvider(BaseScope Scope)
  72:         {
  73:             return Providers.FirstOrDefault(x => x.ProviderScope.Equals(Scope));
  74:         }
  75:  
  76:         #endregion
  77:  
  78:         #region Properties
  79:  
  80:         protected virtual List<IProvider> Providers { get; set; }
  81:  
  82:         #endregion
  83:     }
  84: }

The ProviderManager above holds a list of providers. These providers determine how to handle an implementation when you provide the system with one. The implementations actually determine how something is created. For instance, the code base only has one provider at present called Standard.

   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using Utilities.IoC.Providers.Scope;
  28: using Utilities.IoC.Providers.Interfaces;
  29: using Utilities.IoC.Mappings;
  30: using Utilities.IoC.Providers.Implementations;
  31: #endregion
  32:  
  33: namespace Utilities.IoC.Providers.DefaultProviders
  34: {
  35:     /// <summary>
  36:     /// Standard provider
  37:     /// </summary>
  38:     public class Standard : IProvider
  39:     {
  40:         public IImplementation CreateImplementation(Type ImplementationType, MappingManager MappingManager)
  41:         {
  42:             return new Implementations.Standard(ImplementationType, MappingManager);
  43:         }
  44:  
  45:  
  46:         public BaseScope ProviderScope
  47:         {
  48:             get { return new StandardScope(); }
  49:         }
  50:  
  51:         public IImplementation CreateImplementation(IImplementation Implementation, MappingManager MappingManager)
  52:         {
  53:             return CreateImplementation(Implementation.ReturnType, MappingManager);
  54:         }
  55:  
  56:         public IImplementation CreateImplementation<ImplementationType>(Func<ImplementationType> Implementation)
  57:         {
  58:             return new Delegate<ImplementationType>(Implementation);
  59:         }
  60:     }
  61: }

This provider just creates a new implementation object (either a Delegate or Standard implementation depending) each time it's fed anything. However we could have a provider called Singleton or something and have it return its own implementation types. We determine which provider to use in the ProviderManager based on something called Scopes:

   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: #endregion
  28:  
  29: namespace Utilities.IoC.Providers.Scope
  30: {
  31:     /// <summary>
  32:     /// Standard scope
  33:     /// </summary>
  34:     public class StandardScope : BaseScope
  35:     {
  36:         #region Constructor
  37:  
  38:         public StandardScope()
  39:             : base()
  40:         {
  41:         }
  42:  
  43:         #endregion
  44:  
  45:         #region Properties
  46:  
  47:         public override string Name { get { return "Standard"; } }
  48:  
  49:         #endregion
  50:     }
  51: }

As you can see, it's just a holder of info. So for our Singleton provider example, we would need to create a Singleton scope and have it return that value so we know which to use. Anyway, the next bit is the actual implementations:

   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using Utilities.IoC.Mappings;
  28: using Utilities.IoC.Mappings.Interfaces;
  29: using System.Reflection;
  30: using Utilities.IoC.Mappings.Attributes;
  31: using Utilities.IoC.Providers.BaseClasses;
  32: using Utilities.DataTypes.ExtensionMethods;
  33: using Utilities.Reflection.ExtensionMethods;
  34: #endregion
  35:  
  36: namespace Utilities.IoC.Providers.Implementations
  37: {
  38:     /// <summary>
  39:     /// Standard implementation class
  40:     /// </summary>
  41:     public class Standard : BaseImplementation
  42:     {
  43:         #region Constructor
  44:  
  45:         /// <summary>
  46:         /// Constructor
  47:         /// </summary>
  48:         /// <param name="ImplementationType">Implementation type</param>
  49:         /// <param name="MappingManager">Mapping manager</param>
  50:         public Standard(Type ImplementationType, MappingManager MappingManager)
  51:         {
  52:             this.ReturnType = ImplementationType;
  53:             this.MappingManager = MappingManager;
  54:         }
  55:  
  56:         #endregion
  57:  
  58:         #region Functions
  59:  
  60:         #region Create
  61:  
  62:         public override object Create()
  63:         {
  64:             ConstructorInfo Constructor = Utils.ConstructorList.ChooseConstructor(ReturnType, MappingManager);
  65:             object Instance = CreateInstance(Constructor);
  66:             SetupProperties(Instance);
  67:             SetupMethods(Instance);
  68:             return Instance;
  69:         }
  70:  
  71:         #endregion
  72:  
  73:         #region SetupMethods
  74:  
  75:         private void SetupMethods(object Instance)
  76:         {
  77:             if (Instance.IsNull())
  78:                 return;
  79:             foreach (MethodInfo Method in Instance.GetType().GetMethods().Where(x => IsInjectable(x)))
  80:                 Method.Invoke(Instance, Method.GetParameters().ForEach(x => CreateInstance(x)).ToArray());
  81:         }
  82:  
  83:         #endregion
  84:  
  85:         #region SetupProperties
  86:  
  87:         private void SetupProperties(object Instance)
  88:         {
  89:             if (Instance.IsNull())
  90:                 return;
  91:             Instance.GetType()
  92:                 .GetProperties()
  93:                 .Where(x => IsInjectable(x))
  94:                 .ForEach<PropertyInfo>(x => Instance.SetProperty(x, CreateInstance(x)));
  95:         }
  96:  
  97:         #endregion
  98:  
  99:         #region IsInjectable
 100:  
 101:         private bool IsInjectable(MethodInfo Method)
 102:         {
 103:             return IsInjectable(Method.GetCustomAttributes(false));
 104:         }
 105:  
 106:         private bool IsInjectable(PropertyInfo Property)
 107:         {
 108:             return IsInjectable(Property.GetCustomAttributes(false));
 109:         }
 110:  
 111:         private bool IsInjectable(object[] Attributes)
 112:         {
 113:             return Attributes.OfType<Inject>().Count() > 0;
 114:         }
 115:  
 116:         #endregion
 117:  
 118:         #region CreateInstance
 119:  
 120:         private object CreateInstance(ConstructorInfo Constructor)
 121:         {
 122:             if (Constructor.IsNull() || MappingManager.IsNull())
 123:                 return null;
 124:             List<object> ParameterValues = new List<object>();
 125:             Constructor.GetParameters().ForEach<ParameterInfo>(x => ParameterValues.Add(CreateInstance(x)));
 126:             return Constructor.Invoke(ParameterValues.ToArray());
 127:         }
 128:  
 129:         private object CreateInstance(ParameterInfo Parameter)
 130:         {
 131:             return CreateInstance(Parameter.GetCustomAttributes(false), Parameter.ParameterType);
 132:         }
 133:  
 134:         private object CreateInstance(PropertyInfo Property)
 135:         {
 136:             return CreateInstance(Property.GetCustomAttributes(false), Property.PropertyType);
 137:         }
 138:  
 139:         private object CreateInstance(object[] Attributes, Type Type)
 140:         {
 141:             if (Attributes.Length > 0)
 142:             {
 143:                 foreach (Attribute Attribute in Attributes)
 144:                 {
 145:                     object TempObject = GetObject(Type, Attribute.GetType());
 146:                     if (!TempObject.IsNull())
 147:                         return TempObject;
 148:                 }
 149:             }
 150:             return GetObject(Type);
 151:         }
 152:  
 153:         #endregion
 154:  
 155:         #region GetObject
 156:  
 157:         private object GetObject(Type Type)
 158:         {
 159:             IMapping Mapping = MappingManager.GetMapping(Type);
 160:             return Mapping.IsNull() ? null : Mapping.Implementation.Create();
 161:         }
 162:  
 163:         private object GetObject(Type Type, Type AttributeType)
 164:         {
 165:             IMapping Mapping = MappingManager.GetMapping(Type, AttributeType);
 166:             return Mapping.IsNull() ? null : Mapping.Implementation.Create();
 167:         }
 168:  
 169:         #endregion
 170:  
 171:         #endregion
 172:  
 173:         #region Properties
 174:  
 175:         /// <summary>
 176:         /// Mapping manager
 177:         /// </summary>
 178:         protected virtual MappingManager MappingManager { get; set; }
 179:  
 180:         #endregion
 181:     }
 182: }
   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using Utilities.IoC.Providers.BaseClasses;
  28: #endregion
  29:  
  30: namespace Utilities.IoC.Providers.Implementations
  31: {
  32:     /// <summary>
  33:     /// Delegate implementation
  34:     /// </summary>
  35:     /// <typeparam name="T">Return type of the delegate</typeparam>
  36:     public class Delegate<T> : BaseImplementation
  37:     {
  38:         #region Constructor
  39:  
  40:         /// <summary>
  41:         /// Constructor
  42:         /// </summary>
  43:         /// <param name="Implementation">Implementation delegate</param>
  44:         public Delegate(Func<T> Implementation)
  45:         {
  46:             this.Implementation = Implementation;
  47:             ReturnType = typeof(T);
  48:         }
  49:  
  50:         #endregion
  51:  
  52:         #region Functions
  53:  
  54:         /// <summary>
  55:         /// Creates an object based on a delegate
  56:         /// </summary>
  57:         /// <returns>An object</returns>
  58:         public override object Create()
  59:         {
  60:             return Implementation();
  61:         }
  62:  
  63:         #endregion
  64:  
  65:         #region Properties
  66:  
  67:         /// <summary>
  68:         /// Delegate used to create objects
  69:         /// </summary>
  70:         protected virtual Func<T> Implementation { get; set; }
  71:  
  72:         #endregion
  73:     }
  74: }

You'll notice that the Delegate implementation is a bit simpler. In this case you provide a Func and we just assume you know how you want an item created so we just return it. The standard implementation though is a bit more complicated.

When we call the standard implementation's Create function, it calls this little utility to determine which constructor to use:

   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using System.Reflection;
  28: using Utilities.IoC.Mappings;
  29: #endregion
  30:  
  31: namespace Utilities.IoC.Utils
  32: {
  33:     public static class ConstructorList
  34:     {
  35:         public static ConstructorInfo ChooseConstructor(Type ImplementationType, MappingManager MappingManager)
  36:         {
  37:             ConstructorInfo[] Constructors = ImplementationType.GetConstructors();
  38:             int MaxValue = int.MinValue;
  39:             ConstructorInfo CurrentConstructor = null;
  40:             foreach (ConstructorInfo Constructor in Constructors)
  41:             {
  42:                 int Count = GetParameterCount(Constructor, MappingManager);
  43:                 if (Count > MaxValue)
  44:                 {
  45:                     CurrentConstructor = Constructor;
  46:                     MaxValue = Count;
  47:                 }
  48:             }
  49:             return CurrentConstructor;
  50:         }
  51:  
  52:         private static int GetParameterCount(ConstructorInfo Constructor, MappingManager MappingManager)
  53:         {
  54:             int Count = 0;
  55:             ParameterInfo[] Parameters = Constructor.GetParameters();
  56:             foreach (ParameterInfo Parameter in Parameters)
  57:             {
  58:                 bool Inject = true;
  59:                 object[] Attributes = Parameter.GetCustomAttributes(false);
  60:                 if (Attributes.Length > 0)
  61:                 {
  62:                     foreach (Attribute Attribute in Attributes)
  63:                     {
  64:                         if (MappingManager.GetMapping(Parameter.ParameterType, Attribute.GetType()) != null)
  65:                         {
  66:                             ++Count;
  67:                             Inject = false;
  68:                             break;
  69:                         }
  70:                     }
  71:                 }
  72:                 if (Inject)
  73:                 {
  74:                     if (MappingManager.GetMapping(Parameter.ParameterType) != null)
  75:                         ++Count;
  76:                 }
  77:             }
  78:             if (Count == Parameters.Length)
  79:                 return Count;
  80:             return int.MinValue;
  81:         }
  82:     }
  83: }

This bit of code simply determines which constructor has the most items that we know how to create and returns it. The Standard.Create function then takes that constructor and calls CreateInstance. This call determines the parameters of the constructor, and creates each one in turn using the MappingManager (we'll get to that later). It then feeds the newly created items into the constructor and creates the object. After that it searches each method and each property to determine if they have been marked for injection also (note that this is done using an attribute called Inject). If it finds anything, it creates more objects in the same manner as the parameters for the constructor. Once it's done with that, it returns the newly created object.

So at this point we have our code to actually create our objects but we have nothing mapping it to anything. We can create but we don't know when and we don't know why. That's where the MappingManager comes in.

   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using Utilities.IoC.Mappings.Interfaces;
  28: using System.Reflection;
  29: using Utilities.IoC.Providers;
  30: using Utilities.Reflection.ExtensionMethods;
  31: using Utilities.IoC.Mappings.Internal_Classes;
  32: using Utilities.IoC.Mappings.BaseClasses;
  33: #endregion
  34:  
  35: namespace Utilities.IoC.Mappings
  36: {
  37:     /// <summary>
  38:     /// Mapping manager
  39:     /// </summary>
  40:     public class MappingManager
  41:     {
  42:         #region Constructor
  43:  
  44:         /// <summary>
  45:         /// Constructor
  46:         /// </summary>
  47:         public MappingManager(ProviderManager ProviderManager)
  48:         {
  49:             Modules = new List<IModule>();
  50:             Mappings = new List<IMapping>();
  51:             this.ProviderManager = ProviderManager;
  52:         }
  53:  
  54:         #endregion
  55:  
  56:         #region Functions
  57:  
  58:         /// <summary>
  59:         /// Scans the assembly for mapping modules and creates them
  60:         /// </summary>
  61:         /// <param name="ModuleAssembly"></param>
  62:         public void Setup(Assembly ModuleAssembly)
  63:         {
  64:             IEnumerable<Type> Modules = ModuleAssembly.GetTypes(typeof(IModule));
  65:             List<IModule> TempModules = new List<IModule>();
  66:             foreach (Type Module in Modules)
  67:             {
  68:                 if (!Module.IsInterface && !Module.IsAbstract)
  69:                     TempModules.Add((IModule)Module.Assembly.CreateInstance(Module.FullName));
  70:             }
  71:             foreach (IModule Module in TempModules)
  72:             {
  73:                 Module.Manager = this;
  74:                 Module.Setup();
  75:             }
  76:             this.Modules.AddRange(TempModules);
  77:         }
  78:  
  79:         /// <summary>
  80:         /// Creates a mapping object
  81:         /// </summary>
  82:         /// <param name="ServiceType">Service type</param>
  83:         /// <returns>a mapping object</returns>
  84:         public IMapping CreateMapping(Type ServiceType)
  85:         {
  86:             IMapping Mapping = new Mapping(ServiceType, ProviderManager, this);
  87:             Mappings.Add(Mapping);
  88:             return Mapping;
  89:         }
  90:  
  91:         /// <summary>
  92:         /// Creates a mapping object
  93:         /// </summary>
  94:         /// <param name="ServiceType">Service type</param>
  95:         /// <param name="AttributeType">Attribute type</param>
  96:         /// <returns>A mapping object</returns>
  97:         public IMapping CreateMapping(Type ServiceType, Type AttributeType)
  98:         {
  99:             IMapping Mapping = new Mapping(ServiceType, AttributeType, ProviderManager, this);
 100:             Mappings.Add(Mapping);
 101:             return Mapping;
 102:         }
 103:  
 104:         /// <summary>
 105:         /// Gets the mapping that matches this service type
 106:         /// </summary>
 107:         /// <param name="ServiceType">Service type</param>
 108:         /// <returns>The mapping associated with this service type</returns>
 109:         public IMapping GetMapping(Type ServiceType)
 110:         {
 111:             MappingKey Key = new MappingKey(ServiceType, null, ProviderManager, this);
 112:             return Mappings.Find(x => x.Equals(Key));
 113:         }
 114:  
 115:         /// <summary>
 116:         /// Gets the mapping that matches this service type and attribute type
 117:         /// </summary>
 118:         /// <param name="ServiceType">Service type</param>
 119:         /// <param name="AttributeType">Attribute type</param>
 120:         /// <returns>The mapping associated with this service type and attribute type</returns>
 121:         public IMapping GetMapping(Type ServiceType, Type AttributeType)
 122:         {
 123:             MappingKey Key = new MappingKey(ServiceType, AttributeType, ProviderManager, this);
 124:             return Mappings.Find(x => x.Equals(Key));
 125:         }
 126:  
 127:         #endregion
 128:  
 129:         #region Properties
 130:  
 131:         /// <summary>
 132:         /// Modules listing
 133:         /// </summary>
 134:         protected virtual List<IModule> Modules { get; set; }
 135:  
 136:         /// <summary>
 137:         /// Mapping listing
 138:         /// </summary>
 139:         protected virtual List<IMapping> Mappings { get; set; }
 140:  
 141:         /// <summary>
 142:         /// Provider manager
 143:         /// </summary>
 144:         protected virtual ProviderManager ProviderManager { get; set; }
 145:  
 146:         #endregion
 147:     }
 148: }

The MappingManager is also a bit bare on implementation. All it does is holds a series of mappings and modules and creates them/returns them as necessary. A module is actually not defined inside the system itself. It's what the end user would use to let the system know what mappings to use. It uses the following interface and base class:

   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: #endregion
  28:  
  29: namespace Utilities.IoC.Mappings.Interfaces
  30: {
  31:     /// <summary>
  32:     /// Mapping module interface
  33:     /// </summary>
  34:     public interface IModule
  35:     {
  36:         #region Functions
  37:  
  38:         /// <summary>
  39:         /// Called to setup the module (actual mapping occurs here)
  40:         /// </summary>
  41:         void Setup();
  42:  
  43:         #endregion
  44:  
  45:         #region Properties
  46:  
  47:         MappingManager Manager { get; set; }
  48:  
  49:         #endregion
  50:     }
  51: }
   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using Utilities.IoC.Mappings.Interfaces;
  28: #endregion
  29:  
  30: namespace Utilities.IoC.Mappings.BaseClasses
  31: {
  32:     /// <summary>
  33:     /// Base module class
  34:     /// </summary>
  35:     public abstract class BaseModule : IModule
  36:     {
  37:         #region Functions
  38:  
  39:         public abstract void Setup();
  40:  
  41:         /// <summary>
  42:         /// Creates a mapping using a specific service type
  43:         /// </summary>
  44:         /// <typeparam name="ServiceType">Service type</typeparam>
  45:         /// <returns>A mapping object</returns>
  46:         public virtual IMapping Map<ServiceType>()
  47:         {
  48:             return Map(typeof(ServiceType));
  49:         }
  50:  
  51:         /// <summary>
  52:         /// Creates a mapping using a specific service type and attribute type
  53:         /// </summary>
  54:         /// <typeparam name="ServiceType">Service type</typeparam>
  55:         /// <typeparam name="AttributeType">Attribute type</typeparam>
  56:         /// <returns>A mapping object</returns>
  57:         public virtual IMapping Map<ServiceType, AttributeType>()
  58:         {
  59:             return Map(typeof(ServiceType), typeof(AttributeType));
  60:         }
  61:  
  62:         /// <summary>
  63:         /// Creates a mapping using a specific service type
  64:         /// </summary>
  65:         /// <param name="ServiceType">Service type</param>
  66:         /// <param name="AttributeType">Attribute type</param>
  67:         /// <returns>A mapping object</returns>
  68:         public virtual IMapping Map(Type ServiceType, Type AttributeType = null)
  69:         {
  70:             return Manager.CreateMapping(ServiceType, AttributeType);
  71:         }
  72:  
  73:         #endregion
  74:  
  75:         #region Properties
  76:  
  77:         public virtual MappingManager Manager { get; set; }
  78:  
  79:         #endregion
  80:     }
  81: }

For example, in your code, you would define a module like this:

   1: public class Module : BaseModule
   2: {
   3:     public override void Setup()
   4:     {
   5:         Map<ITestInterface>().To<TestClass1>().SetScope(new StandardScope());
   6:         Map<TestClass1>().To<TestClass1>(() => new TestClass1());
   7:         Map<ITestInterface, MyAttribute>().To(new TestImplementation());
   8:         Map<TestClass2>().To<TestClass2>();
   9:     }
  10: }

This module defines four mappings that the system can use. A mapping is, as the name suggests, a mapping between a key type and what should be created when it encounters that type. For instance whenever I hit the interface ITestInterface, we return a TestClass1 object. The module can also define the scope for the object and sets the implementation used. In the example above the first item maps ITestInterface to TestClass1 and sets the scope to StandardScope. The third item maps ITestInterface items that have the MyAttribute attribute to the TestImplementation implementation. Whenever you call Map in a module, it creates and returns a Mapping class:

   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using Utilities.IoC.Mappings.BaseClasses;
  28: using Utilities.IoC.Providers;
  29: #endregion
  30:  
  31: namespace Utilities.IoC.Mappings.Internal_Classes
  32: {
  33:     /// <summary>
  34:     /// Mapping class
  35:     /// </summary>
  36:     public class Mapping : MappingKey
  37:     {
  38:         #region Constructors
  39:  
  40:         /// <summary>
  41:         /// Constructor
  42:         /// </summary>
  43:         /// <param name="ServiceType">Service type</param>
  44:         public Mapping(Type ServiceType, ProviderManager ProviderManager, MappingManager MappingManager)
  45:             : base(ServiceType, null, ProviderManager, MappingManager)
  46:         {
  47:         }
  48:  
  49:         /// <summary>
  50:         /// Constructor
  51:         /// </summary>
  52:         /// <param name="ServiceType">Service type</param>
  53:         /// <param name="AttributeType">Attribute type</param>
  54:         public Mapping(Type ServiceType, Type AttributeType, ProviderManager ProviderManager, MappingManager MappingManager)
  55:             : base(ServiceType, AttributeType, ProviderManager, MappingManager)
  56:         {
  57:         }
  58:  
  59:         #endregion
  60:     }
  61: }
   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using Utilities.IoC.Mappings.Interfaces;
  28: using Utilities.IoC.Providers;
  29: #endregion
  30:  
  31: namespace Utilities.IoC.Mappings.BaseClasses
  32: {
  33:     /// <summary>
  34:     /// Mapping key
  35:     /// </summary>
  36:     public class MappingKey : BaseMapping
  37:     {
  38:         #region Constructor
  39:  
  40:         public MappingKey(Type ServiceType, Type AttributeType, ProviderManager ProviderManager, MappingManager MappingManager)
  41:             : base(ServiceType, AttributeType, ProviderManager, MappingManager)
  42:         {
  43:         }
  44:  
  45:         #endregion
  46:  
  47:         #region Functions
  48:  
  49:         public override bool Equals(object obj)
  50:         {
  51:             if (!(obj is IMapping))
  52:                 return false;
  53:             IMapping ObjectMapping = (IMapping)obj;
  54:             return ObjectMapping.AttributeType == AttributeType
  55:                 && ObjectMapping.ServiceType == ServiceType;
  56:         }
  57:  
  58:         public override int GetHashCode()
  59:         {
  60:             int AttributeHash = AttributeType == null ? 1 : AttributeType.GetHashCode();
  61:             int ServiceHash = ServiceType == null ? 1 : ServiceType.GetHashCode();
  62:             return ServiceHash * AttributeHash;
  63:         }
  64:  
  65:         #endregion
  66:     }
  67: }
   1: /*
   2: Copyright (c) 2011 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System;
  24: using System.Collections.Generic;
  25: using System.Linq;
  26: using System.Text;
  27: using Utilities.IoC.Mappings.Interfaces;
  28: using Utilities.IoC.Providers;
  29: using Utilities.IoC.Providers.Scope;
  30: using Utilities.IoC.Providers.Interfaces;
  31: #endregion
  32:  
  33: namespace Utilities.IoC.Mappings.BaseClasses
  34: {
  35:     /// <summary>
  36:     /// Base mapping
  37:     /// </summary>
  38:     public class BaseMapping : IMapping
  39:     {
  40:         #region Constructor
  41:  
  42:         /// <summary>
  43:         /// Constructor
  44:         /// </summary>
  45:         /// <param name="ServiceType">Service type</param>
  46:         /// <param name="AttributeType">Attribute type</param>
  47:         public BaseMapping(Type ServiceType, Type AttributeType, ProviderManager ProviderManager, MappingManager MappingManager)
  48:         {
  49:             this.ServiceType = ServiceType;
  50:             this.AttributeType = AttributeType;
  51:             this.ProviderManager = ProviderManager;
  52:             this.MappingManager = MappingManager;
  53:             this.Scope = new StandardScope();
  54:         }
  55:  
  56:         #endregion
  57:  
  58:         #region Functions
  59:  
  60:         public virtual IMapping To<ImplementationType>()
  61:         {
  62:             return To(typeof(ImplementationType));
  63:         }
  64:  
  65:         public virtual IMapping To(Type ImplementationType)
  66:         {
  67:             Implementation = ProviderManager.GetProvider(Scope).CreateImplementation(ImplementationType, MappingManager);
  68:             return this;
  69:         }
  70:  
  71:         public virtual IMapping To<ImplementationType>(Func<ImplementationType> Implementation)
  72:         {
  73:             this.Implementation = ProviderManager.GetProvider(Scope).CreateImplementation(Implementation);
  74:             return this;
  75:         }
  76:  
  77:         public virtual IMapping To(Providers.Interfaces.IImplementation Implementation)
  78:         {
  79:             this.Implementation = Implementation;
  80:             return this;
  81:         }
  82:  
  83:         public virtual IMapping SetScope(BaseScope Scope)
  84:         {
  85:             this.Scope = Scope;
  86:             Implementation = ProviderManager.GetProvider(Scope).CreateImplementation(Implementation, MappingManager);
  87:             return this;
  88:         }
  89:  
  90:         #endregion
  91:  
  92:         #region Properties
  93:  
  94:         public virtual Type ServiceType { get; protected set; }
  95:         public virtual Type AttributeType { get; protected set; }
  96:         public virtual BaseScope Scope { get; protected set; }
  97:         public virtual IImplementation Implementation { get; protected set; }
  98:         protected virtual ProviderManager ProviderManager { get; set; }
  99:         protected virtual MappingManager MappingManager { get; set; }
 100:  
 101:         #endregion
 102:     }
 103: }

The Mapping class is rather empty, the MappingKey actually defines the functions needed to determine which mapping is which. And the BaseMapping class holds the functions that set the scope, set the implementation, etc. And with that we're done.

We create our modules, which sets our mappings, which the system holds for us until we tell the manager to get us a specific object type. Once we do that, it assembles our object for us. It's not that complicated really and not that much code either (the largest file tops out at 189 lines of code including comments). And with that we have ourselves a simple DI container.

If you want updates, or find bugs, etc. check out the repository for the utility library (this is currently under the Utilities.IoC namespace). I'm terrible about updating my site but I update the code there whenever a bug is found. And hopefully I'll finish my huge update to that library before too long (and it is going to contain a number of changes and additions). Anyway, take a look at the code and happy coding.



Comments