zoukankan      html  css  js  c++  java
  • 手动实现一个简单的IOC容器

    1.概述

        IOC:有很多人把控制反转和依赖注入混为一谈,虽然在某种意义上来看他们是一体的,但好像又有些不同。

                   1. IOC(控制反转)是一个控制容器,DI(依赖注入)就是这个容器的运行机制。

                   2. IOC就是一种软件设计思想,DI是这种软件设计思想的一个实现。

        关于Ioc的框架有很多,比如astle Windsor、Unity、Spring.NET、StructureMap,我们这边使用微软提供的Unity做示例,你可以使用 Nuget 添加 Unity ,

    也可以引用Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll。

    2.代码演示

        a.  先介绍常规做法,代码比较简单,稍微看一下:

        public interface IBaseRepository
        {
            void DoSomething();
        }
    
        public interface IRespository : IBaseRepository { }
    
        public interface IUserRepository : IBaseRepository { }
    
        public interface IShopRepository : IBaseRepository { }
    
        public class Repository : IRespository
        {
            public void DoSomething()
            {
                Console.WriteLine("I am a Repository");
            }
        }
    
        public class UserRepository : IUserRepository
        {
            public void DoSomething()
            {
                Console.WriteLine("I am a UserRepository");
            }
        }
    
        public class ShopRepository : IShopRepository
        {
            public void DoSomething()
            {
                Console.WriteLine("I am a ShopRepository");
            }
        }
    
        public interface ITestService
        {
            void DoSomething();
        }
    
        public class TestService : ITestService
        {
            private IRespository respository;
    
            /// <summary>
            /// 构造注入
            /// </summary>
            /// <param name="_respository"></param>
            public TestService(IRespository _respository)
            {
                this.respository = _respository;
            }
    
            /// <summary>
            /// 属性注入
            /// </summary>
            [Dependency]
            public IUserRepository UserRepository { get; set; }
    
            public IShopRepository ShopRepository { get; set; }
    
            /// <summary>
            /// 方法注入
            /// </summary>
            /// <param name="_shopRepository"></param>
            [InjectionMethod]
            public void SetShopRepository(IShopRepository _shopRepository)
            {
                this.ShopRepository = _shopRepository;
            }
    
            public void DoSomething()
            {
                respository.DoSomething();
                UserRepository.DoSomething();
                ShopRepository.DoSomething();
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                UnityContainer container = new UnityContainer();
                container.RegisterType<IRespository, Repository>();
                container.RegisterType<IUserRepository, UserRepository>();
                container.RegisterType<IShopRepository, ShopRepository>();
                container.RegisterType<ITestService, TestService>();
                TestService testService = container.Resolve<ITestService>() as TestService;
                testService.DoSomething();
            }
        }
    View Code

        b. 还有一种是配置文件做法

            这个是配置文件:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <!--要保证configSections为configuration第一个节点-->
      <configSections>
        <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
      </configSections>
      <unity>
        <containers>
          <!--定义了一个名称为defaultContainer的Unity容器-->
          <container name="defaultContainer">
            <register type="Demo.IRespository,Demo" mapTo="Demo.Respository, Demo"/>
            <register type="Demo.IUserRespository,Demo" mapTo="Demo.UserRespository, Demo"/>
            <register type="Demo.IShopRespository,Demo" mapTo="Demo.ShopRespository, Demo"/>
            <register type="Demo.ITestService,Demo" mapTo="Demo.TestService, Demo"/>
          </container>
        </containers>
      </unity>
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
      </startup>
    </configuration>
    View Code

          对应的代码也得改改:

               InitializeComponent();
                //创建容器
                UnityContainer container = new UnityContainer();
                UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection;
                configuration.Configure(container, "defaultContainer");
                //通过Resolve<ITestService>方法返回的是一个类型为TestService的对象,该对象的三个属性被进行了有效的初始化。
                //这个简单的程序分别体现了接口注入(通过相应的接口根据配置解析出相应的实现类型)、构造器注入(属性IRespository)、属性注入(属性IUserRepository)和方法注入(属性IShopRepository)
                TestService t = container.Resolve<ITestService>() as TestService ;
                if (null != t)
                {
                     t.DoSomething();
                }  

    3. Unity的生命周期

          Unity有三种注入方式,构造,属性和方法注入,Unity注入也有自己的生命周期(默认瞬时生命周期:每次都是构造一个新的),下面就介绍下生命周期。

    IUnityContainer container = new UnityContainer();
    //默认瞬时生命周期,每次都是构造一个新的
    container.RegisterType<IA, A>(new TransientLifetimeManager());
    
    //每线程生命周期管理器,就是保证每个线程返回同一实例
    container.RegisterType<IA, A>(new PerThreadLifetimeManager());
    
    //容器控制生命周期管理,这个生命周期管理器是RegisterInstance默认使用的生命周期管理器,也就是单件实例,UnityContainer会维护一个对象实例的强引用,每次调用的时候都会返回同一对象
    container.RegisterType<IA, A>(new ContainerControlledLifetimeManager());
    
    //分层生命周期管理器,这个管理器类似于ContainerControlledLifetimeManager,也是由UnityContainer来管理,也就是单件实例,针对某个层单例
    //不过与ContainerControlledLifetimeManager不同的是,这个生命周期管理器是分层的,因为Unity的容器时可以嵌套的,所以这个生命周期管理器就是针对这种情况,当使用了这种生命周期管理器,父容器和子容器所维护的对象的生命周期是由各自的容器来管理
    container.RegisterType<IA, A>(new HierarchicalLifetimeManager());
    
    //这个生命周期是为了解决循环引用而重复引用的生命周期
    container.RegisterType<IA, A>(new PerResolveLifetimeManager());
    
    //外部控制生命周期管理器,这个生命周期管理允许你使用RegisterType和RegisterInstance来注册对象之间的关系,但是其只会对对象保留一个弱引用,其生命周期交由外部控制,也就是意味着你可以将这个对象缓存或者销毁而不用在意UnityContainer,而当其他地方没有强引用这个对象时,其会被GC给销毁掉。
    //在默认情况下,使用这个生命周期管理器,每次调用Resolve都会返回同一对象(单件实例),如果被GC回收后再次调用Resolve方法将会重新创建新的对象
    container.RegisterType<IA, A>(new ExternallyControlledLifetimeManager());

    4. 自己手动实现简单IOC容器

         怎么自己实现一个简单的IOC容器呢?本次只实现一个简单的版本,生命周期只实现了三种,分别是瞬时,单例和线程单例。

         a.首先定义一个生命周期的枚举 :

    public enum LifeTimeType
        {
            /// <summary>
            /// 瞬时
            /// </summary>
            Transient,
    
            /// <summary>
            /// 单例
            /// </summary>
            Singleton,
    
            /// <summary>
            /// 线程单例
            /// </summary>
            PerThread
        }
    View Code

         b. 定义一个保存注册映射信息的对象:

    public class RegisterInfo
        {
            /// <summary>
            /// 目标类型
            /// </summary>
            public Type TargetType { get; set; }
            /// <summary>
            /// 生命周期
            /// </summary>
            public LifeTimeType LifeTime { get; set; }
        }
    View Code

         c. 定义三个Attribute,直接写一起了:

     [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
        public class DependencyAttribute : Attribute
        {
            public LifeTimeType _lifeTimeType { get; set; }
    
            public DependencyAttribute(LifeTimeType lifeTimeType = LifeTimeType.Transient)
            {
                this._lifeTimeType = lifeTimeType;
            }
        }
    
    
     [AttributeUsage(AttributeTargets.Constructor)]
        public class InjectionConstructorAttribute : Attribute
        {
            public InjectionConstructorAttribute()
            { }
        }
    
        [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
        public class InjectionMethodAttribute : Attribute
        {
            private LifeTimeType _lifeTimeType { get; set; }
    
            public InjectionMethodAttribute(LifeTimeType lifeTimeType = LifeTimeType.Transient)
            {
                this._lifeTimeType = lifeTimeType;
            }
        }
    View Code

         d. 定义一个容器的接口:

        public interface IIOCContainer
        {
            void RegisterType<TFrom, TTo>(LifeTimeType lifeTimeType = LifeTimeType.Transient);
    
            T Resolve<T>();
        }
    View Code

         e. 实现该接口的方法,这是整个容器的关键代码,代码比较长,写的可能有错误,欢迎指正:

    public class IOCContainer : IIOCContainer
        {
            /// <summary>
            /// 缓存注入的配置
            /// </summary>
            private Dictionary<string, RegisterInfo> ContainerDictionary = new Dictionary<string, RegisterInfo>();
    
            /// <summary>
            /// 缓存起来,类型的对象实例
            /// </summary>
            private Dictionary<Type, object> TypeObjectDictionary = new Dictionary<Type, object>();
    
            public void RegisterType<TFrom, TTo>(LifeTimeType lifeTimeType = LifeTimeType.Transient)
            {
                ContainerDictionary.Add(typeof(TFrom).FullName, new RegisterInfo()
                {
                    TargetType = typeof(TTo),
                    LifeTime = lifeTimeType
                });
            }
    
            public T Resolve<T>()
            {
                RegisterInfo info = ContainerDictionary[typeof(T).FullName];
                Type type = ContainerDictionary[typeof(T).FullName].TargetType;
                T result = default(T);
                result = (T)CreateTypeByRegisterType(info, type);
                return result;
            }
    
            private object CreateObject(Type type)
            {
                ConstructorInfo[] ctorArray = type.GetConstructors();
                ConstructorInfo ctor = null;
                if (ctorArray.Count(c => c.IsDefined(typeof(InjectionConstructorAttribute), true)) > 0)
                {
                    ctor = ctorArray.FirstOrDefault(c => c.IsDefined(typeof(InjectionConstructorAttribute), true));
                }
                else
                {
                    ctor = ctorArray.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault();
                }
                List<object> paraList = new List<object>();
                foreach (var parameter in ctor.GetParameters())
                {
                    Type paraType = parameter.ParameterType;
                    RegisterInfo info = ContainerDictionary[paraType.FullName];
                    Type targetType = info.TargetType;
                    object para = null;
                    para = CreateTypeByRegisterType(info, targetType);
                    //递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数
                    paraList.Add(para);
                }
                object objType = Activator.CreateInstance(type, paraList.ToArray());
                //属性注入
                var properties = type.GetProperties()
                                     .Where(p => p.IsDefined(typeof(DependencyAttribute), false)).ToList();
                foreach (var item in properties)
                {
                    var customAttributes =
                        item.GetCustomAttributes(typeof(DependencyAttribute), false) as DependencyAttribute[];
                    if (customAttributes != null)
                    {
                        Type t = item.PropertyType;
                        RegisterInfo info = ContainerDictionary[t.FullName];
                        info.LifeTime = customAttributes.FirstOrDefault()._lifeTimeType;
                        var value = CreateObject(info.TargetType);
                        item.SetValue(objType, value);
                    }
                }
                //字段注入
                var filds = type.GetFields().Where(f => f.IsDefined(typeof(DependencyAttribute), false)).ToList();
                foreach (var fild in filds)
                {
                    var attribute = fild.GetCustomAttribute(typeof(DependencyAttribute)) as DependencyAttribute;
                    if (attribute != null)
                    {
                        Type t = fild.DeclaringType;
                        RegisterInfo info = ContainerDictionary[t.FullName];
                        info.LifeTime = attribute._lifeTimeType;
                        var value = CreateObject(info.TargetType);
                        fild.SetValue(objType, value);
                    }
                }
    
                //方法注入
                var methods = type.GetMethods().Where(m => m.IsDefined(typeof(InjectionMethodAttribute), false)).ToList();
                List<object> paramrterList = new List<object>();
                foreach (var item in methods)
                {
                    var attribute = item.GetCustomAttribute(typeof(InjectionMethodAttribute)) as InjectionMethodAttribute;
                    if (attribute != null)
                    {
                        var parameters = item.GetParameters();
                        foreach (var parameter in parameters)
                        {
                            var paraType = parameter.ParameterType;
                            RegisterInfo info = ContainerDictionary[paraType.FullName];
                            Type targetType = info.TargetType;
                            object para = CreateTypeByRegisterType(info, targetType);
                            //递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数
                            paramrterList.Add(para);
                        }
                        item.Invoke(objType, paramrterList.ToArray());
                    }
                }
                return objType;
            }
    
            private static readonly object obj = new object();
    
            /// <summary>
            /// 根据注入类别创建对象
            /// </summary>
            /// <param name="info"></param>
            /// <param name="targetType"></param>
            /// <returns></returns>
            private object CreateTypeByRegisterType(RegisterInfo info, Type targetType)
            {
                object para = null;
                switch (info.LifeTime)
                {
                    case LifeTimeType.Transient:
                        para = this.CreateObject(targetType);
                        break;
                    case LifeTimeType.Singleton:
                        //需要线程安全 双if+lock
                        if (para == null)
                        {
                            lock (obj)
                            {
                                if (this.TypeObjectDictionary.ContainsKey(targetType))
                                {
                                    para = this.TypeObjectDictionary[targetType];
                                }
                                else
                                {
                                    if (para == null)
                                    {
                                        para = this.CreateObject(targetType);
                                        this.TypeObjectDictionary[targetType] = para;
                                    }
                                }
    
                            }
                        }
                        break;
                    case LifeTimeType.PerThread:
                        //线程单例:线程槽,把数据存在这里
                        {
                            string key = targetType.FullName;
                            object oValue = CallContext.GetData(key);
                            if (oValue == null)
                            {
                                para = this.CreateObject(targetType);
                                CallContext.SetData(key, para);
                            }
                            else
                            {
                                para = oValue;
                            }
                        }
                        break;
                    default:
                        throw new Exception("wrong LifeTime");
                }
                return para;
            }
    
        }
    View Code

    以上代码经过测试,可以使用。

    public interface IImitateScene
        {
            void DoSomeThing();
        }
    
        public class ImitateScene: IImitateScene
        {
            private IUserService userService;
    
            public ImitateScene(IUserService _userService)
            {
                this.userService = _userService;
            }
    
            [Dependency(LifeTimeType.Transient)]
            public IShopService ShopService { get; set; }
    
            public IStoreService StoreService { get; set; }
    
            [InjectionMethod(LifeTimeType.Transient)]
            public void SetStoreService(IStoreService _storeService)
            {
                this.StoreService = _storeService;            
            }
    
            public void DoSomeThing()
            {
                this.userService.DoSomeThing();
                this.StoreService.DoSomeThing();
                this.ShopService.DoSomeThing();
            }
        }
    View Code

     附上项目图,项目结构只为了测试,未做过设计,嘿嘿

    测试结果:

    基本代码就在这里了,还有很多功能未完善,后续有时间会努力研究完善它,造造轮子。

  • 相关阅读:
    在给定的区间上对每个数都开方 最后还是在一段上求和
    简单的覆盖问题,,通过覆盖的g不同 有这不同的价值 最后还是一段上求和
    codevs 3094 寻找sb4
    noi 04:网线主管
    codevs 1031 质数环
    codevs 1061 重复子串
    codevs 1204 寻找子串位置
    codevs 3223 素数密度
    各种用法
    codevs1073 家族
  • 原文地址:https://www.cnblogs.com/bobo-pcb/p/10680773.html
Copyright © 2011-2022 走看看