• IOC控制反转、Unity简介


    参考博客地址:

    Unity系列文章,推荐:http://www.cnblogs.com/qqlin/archive/2012/10/16/2717964.html

    https://www.cnblogs.com/lyps/p/10560256.html

    这篇文章主要介绍.NET Framework下面的IOC以及Unity的使用,下一篇文章介绍.NET Core下面自带的容器IServiceCollection以及Autofac的使用https://www.cnblogs.com/taotaozhuanyong/p/11562184.html

    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 DAL.BaseDAL();
    IBLL.IBaseBll baseBll = new 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); ;
         }
     }
    View Code
     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)}");
        }
    }
    View Code
     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>
    View Code
  • 相关阅读:
    Bootsrap 的 Carousel
    Bootstrap 的 Tooltip 和 Popover
    JavaScript 继承
    Bootstrap 的 Collapse
    Bootstrap 组件之 Panel
    Bootstrap 组件之 List group
    Bootstrap 组件之 Nav
    使用 classList API
    Bootstrap 的 Dropdown
    Bootstrap 的 Modal
  • 原文地址:https://www.cnblogs.com/taotaozhuanyong/p/11562082.html
Copyright © 2020-2023  润新知