IOC控制反转、Unity简介

▼魔方 西西 提交于 2020-04-27 05:32:49

参考博客地址:

 

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

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!