手动实现一个简单的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

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

测试结果:

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

 

posted @ 2019-04-10 00:24  祁临芯  阅读(743)  评论(2编辑  收藏  举报
友情链接:初心商城