浅聊IOC
阅读原文时间:2022年03月02日阅读:1

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();  
    }  
}

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

这个是配置文件:






对应的代码也得改改:

       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(new TransientLifetimeManager());

//每线程生命周期管理器,就是保证每个线程返回同一实例
container.RegisterType(new PerThreadLifetimeManager());

//容器控制生命周期管理,这个生命周期管理器是RegisterInstance默认使用的生命周期管理器,也就是单件实例,UnityContainer会维护一个对象实例的强引用,每次调用的时候都会返回同一对象
container.RegisterType(new ContainerControlledLifetimeManager());

//分层生命周期管理器,这个管理器类似于ContainerControlledLifetimeManager,也是由UnityContainer来管理,也就是单件实例,针对某个层单例
//不过与ContainerControlledLifetimeManager不同的是,这个生命周期管理器是分层的,因为Unity的容器时可以嵌套的,所以这个生命周期管理器就是针对这种情况,当使用了这种生命周期管理器,父容器和子容器所维护的对象的生命周期是由各自的容器来管理
container.RegisterType(new HierarchicalLifetimeManager());

//这个生命周期是为了解决循环引用而重复引用的生命周期
container.RegisterType(new PerResolveLifetimeManager());

//外部控制生命周期管理器,这个生命周期管理允许你使用RegisterType和RegisterInstance来注册对象之间的关系,但是其只会对对象保留一个弱引用,其生命周期交由外部控制,也就是意味着你可以将这个对象缓存或者销毁而不用在意UnityContainer,而当其他地方没有强引用这个对象时,其会被GC给销毁掉。
//在默认情况下,使用这个生命周期管理器,每次调用Resolve都会返回同一对象(单件实例),如果被GC回收后再次调用Resolve方法将会重新创建新的对象
container.RegisterType(new ExternallyControlledLifetimeManager());

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

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

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

public enum LifeTimeType
{
///

/// 瞬时 ///
Transient,

    /// <summary>  
    /// 单例  
    /// </summary>  
    Singleton,

    /// <summary>  
    /// 线程单例  
    /// </summary>  
    PerThread  
}

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

public class RegisterInfo
{
///

/// 目标类型 ///
public Type TargetType { get; set; }
/// /// 生命周期 ///
public LifeTimeType LifeTime { get; set; }
}

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;  
    }  
}

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

public interface IIOCContainer  
{  
    void RegisterType<TFrom, TTo>(LifeTimeType lifeTimeType = LifeTimeType.Transient);

    T Resolve<T>();  
}

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

public class IOCContainer : IIOCContainer
{
///

/// 缓存注入的配置 ///
private Dictionary ContainerDictionary = new Dictionary();

    /// <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)) > )  
        {  
            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;  
    }

}

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

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();  
    }  
}

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

测试结果:

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

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章