参考博客地址:

这篇文章主要介绍.net framework下面的ioc以及unity的使用,下一篇文章介绍.net core下面自带的容器iservicecollection以及autofac的使用

ioc(inverse of control),控制反转。

说到ioc,就不得不提di(dependency injection),依赖注入

ioc是目标效果,需要di依赖注入的手段。

分层架构时这些是必须的,可以划分边界独立演化,也方便分工,促进代码复用。。

依赖倒置原则dip:

  系统架构时,高层模块不应该依赖于低层模块,二者通过抽象来依赖。依赖抽象而不是依赖细节。在a勒种调用了b类,a类就是高层,b类就是低层。

面向抽象:

  1、一个方法满足多种类型

  2、致辞下层的扩展。

下面有三种创建一个对象的方式:

androidphone phone = new androidphone();//1 全是细节

iphone phone = new androidphone();//2 左边抽象右边细节

iphone phone = objectfactory.createphone();//3 封装转移
/// <summary>
/// 简单工厂+配置文件+反射
/// </summary>
public class objectfactory
{
    public static iphone createphone()
    {
        string classmodule = configurationmanager.appsettings["iphonetype"];
        assembly assemly = assembly.load(classmodule.split(',')[1]);
        type type = assemly.gettype(classmodule.split(',')[0]);
        return (iphone)activator.createinstance(type);//无参数构造函数
    }

    public static iphone createphone(ibasebll ibll)
    {
        string classmodule = configurationmanager.appsettings["iphonetype"];
        assembly assemly = assembly.load(classmodule.split(',')[1]);
        type type = assemly.gettype(classmodule.split(',')[0]);
        return (iphone)activator.createinstance(type, new object[] { ibll });
    }
}

在app.config下面配置节点:

<appsettings>
    <add key="iphonetype" value="bingle.service.androidphone,bingle.service" />
  </appsettings>

只有抽象,没有细节,好处是可扩展。

ioc控制反转:

  传统开发,上端依赖(调用/指定)下端对象,这个样子会有依赖。控制反转就是把对下端对象的依赖转移到第三方容器(工厂+配置文件+反射),能够让程序拥有更好的扩展性。

下面出现一个问题:

  构造a对象,但是a依赖于b对象,那就先构造b,如果b又依赖c,再构造c。。。。。。

idal.ibasedal basedal = new ruamou.dal.basedal();
ibll.ibasebll basebll = new ruanmou.bll.basebll(basedal);
iphone phone = objectfactory.createphone(basebll);

现在这个问题已经暴露了,下面开始了di,依赖注入,就能做到构造某个对象时,将依赖的对象自动初始化并注入。

ioc是目标效果,需要di依赖注入的手段。

di依赖注入:

  三种方式注入:构造函数注入、属性注入、方法注入(按照时间顺序)

  [dependency]//属性注入

 [dependency]//属性注入
 public imicrophone imicrophone { get; set; }

  [injectionconstructor]//构造函数注入,默认找参数最多的构造函数,方法注入不加这个特性也是可以的,可以不用特性,可以去掉对容器的依赖

[injectionconstructor]//构造函数注入:默认找参数最多的构造函数
public applephoneupdate(iheadphone headphone)
{
    this.iheadphone = headphone;
    console.writeline("{0} 带参数构造函数", this.gettype().name);
}

  [injectionmethod]//方法注入

 [injectionmethod]//方法注入
 public void init(ipower power)
 {
     this.ipower = power;
 }

如何使用unity容器?

  1、安装unity

  

 

   2、容器三部曲:

    实例化容器、注册类型、获取实例

  3、项目版本和服务处的版本要一直。

下面是iphone与androidphone的定义:

 public interface iphone
 {
     void call();
     imicrophone imicrophone { get; set; }
     iheadphone iheadphone { get; set; }
     ipower ipower { get; set; }
 }




 public class androidphone : iphone
 {
     public imicrophone imicrophone { get; set; }
     public iheadphone iheadphone { get; set; }
     public ipower ipower { get; set; }

     //public androidphone()
     //{
     //    console.writeline("{0}构造函数", this.gettype().name);
     //}
     
     public androidphone(abstractpad pad, iheadphone headphone)
     {
         console.writeline("{0}构造函数", this.gettype().name);
     }

     //[eleveninjectionconstructor]
     public androidphone(abstractpad pad)
     {
         console.writeline("{0}构造函数", this.gettype().name);
     }
     public androidphone(ibasebll basebll)
     {
         console.writeline("{0}构造函数", this.gettype().name);
     }

     public void call()
     {
         console.writeline("{0}打电话", this.gettype().name); ;
     }
 }
 iunitycontainer container = new unitycontainer();//1 实例化容器
 container.registertype<iphone, androidphone>();//2 注册类型
 iphone iphone = container.resolve<iphone>();//3 获取实例

我们来看一下unity下面registertype方法里面的泛型约束:

 

还有一个方法:

 

 

iunitycontainer container = new unitycontainer();//1 实例化容器

container.registerinstance<abstractpad>(new applepadchild());

abstractpad abstractpad = container.resolve<abstractpad>();

后遭的时候,有依赖:

 

 下面来解决这个问题:但是要保持unity版本一致

下面是一些注册时要依赖的类型

 public interface iheadphone
 {

 }

 public class headphone : iheadphone
 {
     public headphone(imicrophone microphone)
     {
         console.writeline("headphone 被构造");
     }
 }
public interface imicrophone
{

}

 public class microphone : imicrophone
 {

     public microphone(ipower power)
     {
         console.writeline("microphone 被构造");
     }
 }
public interface ipower
{

}

public class power : ipower
{
    public power(ibll.ibasebll basebll)
    {
        console.writeline("power 被构造");
    }
}
 public interface ibasebll
 {
     void dosomething();
 }
 public class basebll : ibasebll
 {
     private ibasedal _basedal = null;
     public basebll(ibasedal basedal, int id)
     {
         console.writeline($"{nameof(basebll)}被构造。。。{id}。");
         this._basedal = basedal;
     }
     public void dosomething()
     {
         this._basedal.add();
         this._basedal.update();
         this._basedal.find();
         this._basedal.delete();
     }
 }

 public interface ibasedal
 {
     void add();
     void delete();
     void update();
     void find();
 }
public class basedal : ibasedal
{
    public basedal()
    {
        console.writeline($"{nameof(basedal)}被构造。。。。");
    }

    public void add()
    {
        console.writeline($"{nameof(add)}");
    }

    public void delete()
    {
        console.writeline($"{nameof(delete)}");
    }

    public void find()
    {
        console.writeline($"{nameof(find)}");
    }

    public void update()
    {
        console.writeline($"{nameof(update)}");
    }
}

 

 iunitycontainer container = new unitycontainer();
 container.registertype<iphone, applephone>();
 container.registertype<iheadphone, headphone>();
 container.registertype<imicrophone, microphone>();
 container.registertype<ipower, power>();
 container.registertype<ibll.ibasebll, bll.basebll>();
 container.registertype<idal.ibasedal, ruamou.dal.basedal>();
 iphone iphone = container.resolve<iphone>();

但凡是用到了需要的类型,都要给注入进去,不然容器怎么知道类型啊

 

unity里面到底是怎么实现的?下面,自己来写一个ioc

1、最最基础简陋的版本:

public interface iltcontainer
    {
        void registertype<tfrom, tto>();
        t resolve<t>();
    }

 /// <summary>
    /// 容器--工厂
    /// </summary>
    public class ltcontainer : iltcontainer
    {
        private dictionary<string, type> ltdic = new dictionary<string, type>();

        public void registertype<tfrom, tto>()
        {
            ltdic.add(typeof(tfrom).fullname, typeof(tto));
        }

        public t resolve<t>()
        {
            type type = ltdic[typeof(t).fullname];
            return (t)activator.createinstance(type);
        }
    }
}

调用一下:

iltcontainer container = new ltcontainer();
container.registertype<iperson, student>();

var person = container.resolve<iperson>();

 

2、升级一点点

 

 

  public interface iperson
    {

    }

    public class student : iperson
    {
        [ltinjectionconstructor]
        public student(animal animal)
        {
            console.writeline("student被构造了...");
        }

    }

    public abstract class animal
    {
    }

    public class cat : animal
    {
        public cat()
        {
            console.writeline("animal被构造了....");
        }
    }
}
  public interface iltcontainer
    {
        void registertype<tfrom, tto>();
        t resolve<t>();
    }


    /// <summary>
    /// 容器--工厂
    /// </summary>
    public class ltcontainer : iltcontainer
    {
        private dictionary<string, type> ltdic = new dictionary<string, type>();

        public void registertype<tfrom, tto>()
        {
            ltdic.add(typeof(tfrom).fullname, typeof(tto));
        }

        public t resolve<t>()
        {
            type type = ltdic[typeof(t).fullname];
            var ctorarray = type.getconstructors();
            constructorinfo ctor = null;
            if (ctorarray.count(c => c.isdefined(typeof(ltinjectionconstructorattribute), true)) > 0)
            {
                ctor = ctorarray.firstordefault(c => c.isdefined(typeof(ltinjectionconstructorattribute), true));
            }
            else
            {
                ctor = ctorarray.orderbydescending(c => c.getparameters().length).firstordefault();
            }
            list<object> paralist = new list<object>();
            foreach (var item in ctor.getparameters())
            {
                type paratype = item.parametertype;
                type targettype = this.ltdic[paratype.fullname];
                paralist.add(activator.createinstance(targettype));
            }
            return (t)activator.createinstance(type, paralist.toarray());
            //return (t)this.createobject(type);

        }

        private object createobject(type type)
        {
            constructorinfo[] ctorarray = type.getconstructors();
            constructorinfo ctor = null;
            if (ctorarray.count(c => c.isdefined(typeof(ltinjectionconstructorattribute), true)) > 0)
            {
                ctor = ctorarray.firstordefault(c => c.isdefined(typeof(ltinjectionconstructorattribute), 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;
                type targettype = this.ltdic[paratype.fullname];
                object para = this.createobject(targettype);
                //递归:隐形的跳出条件,就是getparameters结果为空,targettype拥有无参数构造函数
                paralist.add(para);
            }
            return activator.createinstance(type, paralist.toarray());
        }
        //属性注入+方法注入?

    }

调用一下:

iltcontainer container = new ltcontainer();
 iltcontainer container = new ltcontainer();
container.registertype<iperson, student>();
container.registertype<animal, cat>();
var person = container.resolve<iperson>();

3、再升级一点点:

  继续找出targettype的构造,找出一个合适的构造函数,分别构造其参数,继续…递归

 

 

 public interface iltcontainer
    {
        void registertype<tfrom, tto>();
        t resolve<t>();
    }


    /// <summary>
    /// 容器--工厂
    /// </summary>
    public class ltcontainer : iltcontainer
    {
        private dictionary<string, type> ltdic = new dictionary<string, type>();

        public void registertype<tfrom, tto>()
        {
            ltdic.add(typeof(tfrom).fullname, typeof(tto));
        }

        public t resolve<t>()
        {
            type type = ltdic[typeof(t).fullname];
            //继续找出targettype的构造函数,找出一个合适的构造函数,分别构造其参数
            //继续......递归
            return (t)this.createobject(type);

        }


        public object createobject(type type)
        {
            constructorinfo[] ctorarray = type.getconstructors();
            constructorinfo ctor = null;
            if (ctorarray.count(c => c.isdefined(typeof(ltcontainer), true)) > 0)
            {
                ctor = ctorarray.firstordefault(c => c.isdefined(typeof(ltcontainer), 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;
                type targettype = this.ltdic[paratype.fullname];
                object para = this.createobject(targettype);
                //递归:隐形的跳出条件,就是getparameters结果为空,targettype拥有无参数构造函数
                paralist.add(para);
            }
            return activator.createinstance(type, paralist.toarray());
        }
        //属性注入+方法注入?

    }

 

生命管理周期:

iunitycontainer container = new unitycontainer();

默认瞬时生命周期:每次都是构造一个新的

container.registertype<abstractpad, applepad>();
container.registertype<abstractpad, applepad>(new transientlifetimemanager());

全局单例:全局就只有一个该类型实例

非强制性,只有通过容器获取才是单例;项目中一般推荐容器单例而不是自己写单例

container.registertype<abstractpad, applepad>(new singletonlifetimemanager());
abstractpad pad1 = container.resolve<abstractpad>();
abstractpad pad2 = container.resolve<abstractpad>();
console.writeline(object.referenceequals(pad1, pad2));

线程单例:同一个线程就只有一个实例,不同线程就是不同实例

container.registertype<abstractpad, applepad>(new perthreadlifetimemanager());
abstractpad pad1 = null;
abstractpad pad2 = null;
abstractpad pad3 = null;

action act1 = new action(() =>
                {
                    pad1 = container.resolve<abstractpad>();
                    console.writeline($"pad1由线程id={thread.currentthread.managedthreadid}");
                });
var result1 = act1.begininvoke(null, null);

action act2 = new action(() =>
{
    pad2 = container.resolve<abstractpad>();
    console.writeline($"pad2由线程id={thread.currentthread.managedthreadid}");
});
var result2 = act2.begininvoke(t =>
{
    pad3 = container.resolve<abstractpad>();
    console.writeline($"pad3由线程id={thread.currentthread.managedthreadid}");
    console.writeline($"object.referenceequals(pad2, pad3)={object.referenceequals(pad2, pad3)}");
}, null);

act1.endinvoke(result1);
act2.endinvoke(result2);

console.writeline($"object.referenceequals(pad1, pad2)={object.referenceequals(pad1, pad2)}");

//externallycontrolledlifetimemanager 外部可释放单例
//perresolvelifetimemanager 循环引用

 

 自己写的容器里面,加上生命周期:

 public interface ibinglecontainer
 {
     void registertype<tfrom, tto>(lifetimetype lifetimetype = lifetimetype.transient);
     t resolve<t>();
 }

 /// <summary>
 /// 容器--工厂
 /// </summary>
 public class binglecontainer : ibinglecontainer
 {
     private dictionary<string, registerinfo> binglecontainerdictionary = new dictionary<string, registerinfo>();
     

     /// <summary>
     /// 缓存起来,类型的对象实例
     /// </summary>
     private dictionary<type, object> typeobjectdictionary = new dictionary<type, object>();

     /// <summary>
     /// 
     /// </summary>
     /// <typeparam name="tfrom"></typeparam>
     /// <typeparam name="tto"></typeparam>
     /// <param name="lifetimetype">默认参数,不传递就是transient</param>
     public void registertype<tfrom, tto>(lifetimetype lifetimetype = lifetimetype.transient)
     {
         binglecontainerdictionary.add(typeof(tfrom).fullname, new registerinfo()
         {
             targettype = typeof(tto),
             lifetime = lifetimetype
         });
     }

     public t resolve<t>()
     {
         registerinfo info = binglecontainerdictionary[typeof(t).fullname];
         type type = binglecontainerdictionary[typeof(t).fullname].targettype;
         t result = default(t);
         switch (info.lifetime)
         {
             case lifetimetype.transient:
                 result = (t)this.createobject(type);
                 break;
             case lifetimetype.singleton:
                 if (this.typeobjectdictionary.containskey(type))
                 {
                     result = (t)this.typeobjectdictionary[type];
                 }
                 else
                 {
                     result = (t)this.createobject(type);
                     this.typeobjectdictionary[type] = result;
                 }
                 break;
             case lifetimetype.perthread:
                 //怎么保证用线程校验呢? 线程槽,把数据存在这里
                 {
                     string key = type.fullname;
                     object ovalue = callcontext.getdata(key);
                     if (ovalue == null)
                     {
                         result = (t)this.createobject(type);
                         callcontext.setdata(key, result);
                     }
                     else
                     {
                         result = (t)ovalue;
                     }
                 }
                 break;
             default:
                 throw new exception("wrong lifetime");
         }
         return result;
     }
     private object createobject(type type)
     {
         constructorinfo[] ctorarray = type.getconstructors();
         constructorinfo ctor = null;
         if (ctorarray.count(c => c.isdefined(typeof(bingleinjectionconstructorattribute), true)) > 0)
         {
             ctor = ctorarray.firstordefault(c => c.isdefined(typeof(bingleinjectionconstructorattribute), 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 = binglecontainerdictionary[paratype.fullname];
             type targettype = info.targettype;
             //object para = this.createobject(targettype);
             object para = null;
             #region 
                {
                    switch (info.lifetime)
                    {
                        case lifetimetype.transient:
                            para = this.createobject(targettype);
                            break;
                        case lifetimetype.singleton:
                            //需要线程安全 双if+lock
                            {
                                if (this.typeobjectdictionary.containskey(targettype))
                                {
                                    para = this.typeobjectdictionary[targettype];
                                }
                                else
                                {
                                    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");
                    }
                }
                #endregion
             //递归:隐形的跳出条件,就是getparameters结果为空,targettype拥有无参数构造函数
             paralist.add(para);
         }
         return activator.createinstance(type, paralist.toarray());
     }
     //属性注入+方法注入?


 }
public class registerinfo
{
    /// <summary>
    /// 目标类型
    /// </summary>
    public type targettype { get; set; }
    /// <summary>
    /// 生命周期
    /// </summary>
    public lifetimetype lifetime { get; set; }
}

public enum lifetimetype
{
    transient,
    singleton,
    perthread
}
 ibinglecontainer container = new binglecontainer();
 container.registertype<iphone, androidphone>(lifetimetype.perthread);
 container.registertype<abstractpad, applepad>(lifetimetype.perthread);
 container.registertype<iheadphone, headphone>(lifetimetype.transient);
 container.registertype<imicrophone, microphone>(lifetimetype.singleton);
 container.registertype<ipower, power>();
 container.registertype<ibll.ibasebll, bll.basebll>();
 container.registertype<idal.ibasedal, ruamou.dal.basedal>();
 iphone pad1 = null;
 iphone pad2 = null;
 iphone pad3 = null;
 //pad1 = container.resolve<iphone>();
 action act1 = new action(() =>
 {
     pad1 = container.resolve<iphone>();
     console.writeline($"pad1由线程id={thread.currentthread.managedthreadid}");
 });
 var result1 = act1.begininvoke(null, null);

 action act2 = new action(() =>
 {
     pad2 = container.resolve<iphone>();
     console.writeline($"pad2由线程id={thread.currentthread.managedthreadid}");
 });
 var result2 = act2.begininvoke(t =>
 {
     pad3 = container.resolve<iphone>();
     console.writeline($"pad3由线程id={thread.currentthread.managedthreadid}");
     console.writeline($"object.referenceequals(pad2, pad3)={object.referenceequals(pad2, pad3)}");
 }, null);

 act1.endinvoke(result1);
 act2.endinvoke(result2);

 console.writeline($"object.referenceequals(pad1, pad2)={object.referenceequals(pad1, pad2)}");

 

 容器依赖细节?如果不想依赖细节,又想创建对象,反射+配置文件:

 execonfigurationfilemap filemap = new execonfigurationfilemap();
 filemap.execonfigfilename = path.combine(appdomain.currentdomain.basedirectory + "cfgfiles\\unity.config");//找配置文件的路径
 configuration configuration = configurationmanager.openmappedexeconfiguration(filemap, configurationuserlevel.none);
 unityconfigurationsection section = (unityconfigurationsection)configuration.getsection(unityconfigurationsection.sectionname);

 iunitycontainer container = new unitycontainer();
 section.configure(container, "testcontainer1");

 // container.addnewextension<interception>().configure<interception>()
 //.setinterceptorfor<iphone>(new interfaceinterceptor());

 iphone phone = container.resolve<iphone>();
 phone.call();
 iphone android = container.resolve<iphone>("android");
 android.call();

 idbcontext<program> context = container.resolve<idbcontext<program>>();
 context.donothing();

配置文件:

 <unity>
   <!--<sectionextension type="microsoft.practices.unity.interceptionextension.configuration.interceptionconfigurationextension, microsoft.practices.unity.interception.configuration"/>-->
   <sectionextension type="microsoft.practices.unity.interceptionextension.configuration.interceptionconfigurationextension, unity.interception.configuration"/>
   <containers>
     <container name="testcontainer1">
       <extension type="interception"/>
       <register type="bingle.interface.iphone,bingle.interface" mapto="bingle.service.applephone, bingle.service"/>
       <!--是dll名称,不是命名空间-->
       <register type="bingle.interface.iphone,bingle.interface" mapto="bingle.service.androidphone, bingle.service" name="android">
         <!--别名-->
         <interceptor type="interfaceinterceptor"/>
         <interceptionbehavior type="bingle.framework.aop.logbeforebehavior, bingle.framework"/>
         <interceptionbehavior type="bingle.framework.aop.logafterbehavior, bingle.framework"/>
         <interceptionbehavior type="bingle.framework.aop.parametercheckbehavior, bingle.framework"/>
         <lifetime type="transient" />
       </register>

       <register type="bingle.interface.imicrophone, bingle.interface" mapto="bingle.service.microphone, bingle.service"/>
       <register type="bingle.interface.iheadphone, bingle.interface" mapto="bingle.service.headphone, bingle.service"/>
       <register type="bingle.interface.ipower, bingle.interface" mapto="bingle.service.power, bingle.service"/>
       <register type="bingle.interface.abstractpad, bingle.interface" mapto="bingle.service.applepad, bingle.service"/>
       <register type="bingle.ibll.ibasebll, bingle.ibll" mapto="bingle.bll.basebll, bingle.bll">
         <constructor>
           <param name="basedal" type="bingle.idal.ibasedal, bingle.idal"  />
           <param name="id" type="system.int32" value="3" />
         </constructor>
       </register>
       <register type="bingle.idal.ibasedal, bingle.idal" mapto="ruamou.dal.basedal, ruamou.dal"/>
       <register type="bingle.idal.idbcontext`1, bingle.idal" mapto="ruamou.dal.dbcontextdal`1, ruamou.dal"/>
     </container>
    <unity>