Creating a small IoC container in C #

I decided to create a very small IoC container in C # for the MonoGame project. The reason I decided to create it myself was to improve performance and use fewer libraries that I don't control. Since IoC is something so simple, I don't think the library should handle it.

I started a naive implementation:

var container = new Container();
container.Register("service-alias",
    container => new ServiceClass(container.Resolve("other.dep"));

container.Resolve("service-alias").MethodOnServiceClass()

But I have no idea how to do this in a system like C #. A Dictionary <string, Func<Container>>? How to introduce a return permission method?

+4
source share
3 answers

21 . , , , , ( ). , DI. , , Pure DI ( : DI DI) Pure DI DI , - , Root Composition .

+9

.

1) " IoC " . - :

public interface IContainer 
{
    void RegisterType<TSource, TDestination>();
    void RegisterType<TSource>(Func<TSource, TDestination> generator);
    T Resolve<T>(); 
}

2) , . Autofac, .

3) , " IoC".

4) - , IoC ( ), IoC, , . , , IoC- (, ).

:

  • IoC ( ), . .
  • .
  • IoC ( ). (, , ) " , ".

, , . .

, .

0

,


using System;
using System.Linq;

namespace IOC
{
    /// <summary>
    /// Ioc Container
    /// </summary>
    public class Container
    {
        private readonly System.Collections.Generic.Dictionary<Type, Type> map = new System.Collections.Generic.Dictionary<Type, Type>();
        public string Name { get; private set; }
        public Container(string containerName)
        {
            Name = containerName;
            System.Diagnostics.Trace.TraceInformation("New instance of {0} created", Name);
        }

        /// <summary>
        /// Register the mapping for inversion of control
        /// </summary>
        /// <typeparam name="From">Interface </typeparam>
        /// <typeparam name="To">Insatnce</typeparam>
        public void Register<From,To>()
        {
            try
            {
                map.Add(typeof(From), typeof(To));
                System.Diagnostics.Trace.TraceInformation("Registering {0} for {1}", typeof(From).Name, typeof(To).Name);
            }
            catch(Exception registerException)
            {
                System.Diagnostics.Trace.TraceError("Mapping Exception", registerException);
                throw new IocException("Mapping Exception",registerException);
            }
        }

        /// <summary>
        /// Resolves the Instance 
        /// </summary>
        /// <typeparam name="T">Interface</typeparam>
        /// <returns></returns>
        public T Resolve<T>()
        {
            return (T)Resolve(typeof(T));
        }

        private object Resolve(Type type)
        {
            Type resolvedType = null;
            try
            {
                resolvedType = map[type];
                System.Diagnostics.Trace.TraceInformation("Resolving {0}", type.Name);
            }
            catch(Exception resolveException)
            {
                System.Diagnostics.Trace.TraceError("Could't resolve type", resolveException);
                throw new IocException("Could't resolve type", resolveException);
            }

            var ctor = resolvedType.GetConstructors().First();
            var ctorParameters = ctor.GetParameters();
            if(ctorParameters.Length ==0)
            {
                System.Diagnostics.Trace.TraceInformation("Constructor have no parameters");
                return Activator.CreateInstance(resolvedType);
            }

            var parameters = new System.Collections.Generic.List<object>();
            System.Diagnostics.Trace.TraceInformation("Constructor found to have {0} parameters",ctorParameters.Length);

            foreach (var p in ctorParameters)
            {
                parameters.Add(Resolve(p.ParameterType));
            }

            return ctor.Invoke(parameters.ToArray());
        }
    }
}

0

Source: https://habr.com/ru/post/1607292/


All Articles