IOC控制反转、Unity简介
<p>参考博客地点:</p><p> </p>
<p>Unity系列文章,推荐:http://www.cnblogs.com/qqlin/archive/2012/10/16/2717964.html</p>
<p>https://www.cnblogs.com/lyps/p/10560256.html<br /></p>
<p> </p>
<p><strong>这篇文章紧张先容.NET Framework下面的IOC以及Unity的使用,下一篇文章先容.NET Core下面自带的容器IServiceCollection以及Autofac的使用https://www.cnblogs.com/taotaozhuanyong/p/11562184.html</strong></p>
<p>IOC(Inverse of Control),控制反转。</p>
<p>说到IOC,就不得不提DI(Dependency Injection),依赖注入</p>
<p>IOC是目的结果,需要DI依赖注入的手段。</p>
<p>分层架构时这些是必须的,可以分别边界独立演化,也方便分工,促进代码复用。。</p>
<p>依赖倒置原则DIP:</p>
<p> 体系架构时,高层模块不应该依赖于低层模块,二者通过抽象来依赖。依赖抽象而不是依赖细节。在A勒种调用了B类,A类就是高层,B类就是低层。</p>
<p>面向抽象:</p>
<p> 1、一个方法满意多种范例</p>
<p> 2、支持下层的扩展。</p>
<p>下面有三种创建一个对象的方式:</p>
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(','));
Type type = assemly.GetType(classModule.Split(','));
return (IPhone)Activator.CreateInstance(type);//无参数构造函数
}
public static IPhone CreatePhone(IBaseBll iBLL)
{
string classModule = ConfigurationManager.AppSettings["iPhoneType"];
Assembly assemly = Assembly.Load(classModule.Split(','));
Type type = assemly.GetType(classModule.Split(','));
return (IPhone)Activator.CreateInstance(type, new object[] { iBLL });
}
}
<p>在App.config下面设置节点:</p>
<appSettings>
<add key="iPhoneType" value="Bingle.Service.AndroidPhone,Bingle.Service" />
</appSettings>
<p>只有抽象,没有细节,好处是可扩展。</p>
<p>IOC控制反转:</p>
<p> 传统开辟,上端依赖(调用/指定)下端对象,这个样子会有依赖。控制反转就是把对下端对象的依赖转移到第三方容器(工厂+设置文件+反射),能够让程序拥有更好的扩展性。</p>
<p>下面出现一个题目:</p>
<p> 构造A对象,但是A依赖于B对象,那就先构造B,如果B又依赖C,再构造C。。。。。。</p>
IDAL.IBaseDAL baseDAL = new Ruamou.DAL.BaseDAL();
IBLL.IBaseBll baseBll = new Ruanmou.BLL.BaseBll(baseDAL);
IPhone phone = ObjectFactory.CreatePhone(baseBll);
<p>如今这个题目已经袒露了,下面开始了DI,依赖注入,就能做到构造某个对象时,将依赖的对象自动初始化并注入。</p>
<p>IOC是目的结果,需要DI依赖注入的手段。</p>
<p>DI依赖注入:</p>
<p> 三种方式注入:构造函数注入、属性注入、方法注入(按照时间顺序)</p>
<p> //属性注入</p>
//属性注入
public IMicrophone iMicrophone { get; set; }
<p> //构造函数注入,默认找参数最多的构造函数,方法注入不加这个特性也是可以的,可以不消特性,可以去掉对容器的依赖</p>
//构造函数注入:默认找参数最多的构造函数
public ApplePhoneUpdate(IHeadphone headphone)
{
this.iHeadphone = headphone;
Console.WriteLine("{0} 带参数构造函数", this.GetType().Name);
}
<p> //方法注入</p>
//方法注入
public void Init(IPower power)
{
this.iPower = power;
}
<p>如何使用Unity容器?</p>
<p> 1、安装Unity</p>
<p> <div align="center"></div></p>
<p> </p>
<p> 2、容器三部曲:</p>
<p> 实例化容器、注册范例、获取实例</p>
<p> 3、项目版本和服务处的版本要不绝。</p>
<p>下面是Iphone与AndroidPhone的界说:</p>
<div align="center"></div><div align="center"></div>
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);
}
//
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 获取实例
<p>我们来看一下Unity下面RegisterType方法内里的泛型束缚:</p>
<p><div align="center"></div></p>
<p> </p>
<p>另有一个方法:</p>
<p><div align="center"></div></p>
<p> </p>
<p> </p>
IUnityContainer container = new UnityContainer();//1 实例化容器
container.RegisterInstance<AbstractPad>(new ApplePadChild());
AbstractPad abstractPad = container.Resolve<AbstractPad>();
<p>后遭的时间,有依赖:</p>
<p><div align="center"></div></p>
<p> </p>
<p> 下面来解决这个题目:但是要保持Unity版本同等</p>
<p>下面是一些注册时要依赖的范例</p>
<div align="center"></div><div align="center"></div>
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
<p> </p>
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>();
<p>但凡是用到了需要的范例,都要给注入进去,否则容器怎么知道范例啊</p>
<p> </p>
<p><strong>Unity内里到底是怎么实现的?下面,自己来写一个IOC</strong></p>
<p><strong>1、最最根本大略的版本:</strong></p>
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;
return (T)Activator.CreateInstance(type);
}
}
}
<p>调用一下:</p>
ILTContainer container = new LTContainer();
container.RegisterType<IPerson, Student>();
var person = container.Resolve<IPerson>();
<p> </p>
<p><strong>2、升级一点点</strong></p>
<p><div align="center"></div></p>
<p> </p>
<p> </p>
public interface IPerson
{
}
public class Student : IPerson
{
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;
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;
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;
object para = this.CreateObject(targetType);
//递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数
paraList.Add(para);
}
return Activator.CreateInstance(type, paraList.ToArray());
}
//属性注入+方法注入?
}
<p>调用一下:</p>
ILTContainer container = new LTContainer();
ILTContainer container = new LTContainer();
container.RegisterType<IPerson, Student>();
container.RegisterType<Animal, Cat>();
var person = container.Resolve<IPerson>();
<p><strong>3、再升级一点点:</strong></p>
<p> 继承找出targetType的构造,找出一个符合的构造函数,分别构造其参数,继承...递归</p>
<p><div align="center"></div></p>
<p> </p>
<p> </p>
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;
//继承找出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;
object para = this.CreateObject(targetType);
//递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数
paraList.Add(para);
}
return Activator.CreateInstance(type, paraList.ToArray());
}
//属性注入+方法注入?
}
<p> </p>
<p><strong>生命管理周期:</strong></p>
IUnityContainer container = new UnityContainer();
<p><strong>默认瞬时生命周期</strong>:每次都是构造一个新的</p>
container.RegisterType<AbstractPad, ApplePad>();
container.RegisterType<AbstractPad, ApplePad>(new TransientLifetimeManager());
<p><strong>全局单例</strong>:全局就只有一个该范例实例</p>
<p>非欺压性,只有通过容器获取才是单例;项目中一般推荐容器单例而不是自己写单例</p>
container.RegisterType<AbstractPad, ApplePad>(new SingletonLifetimeManager());
AbstractPad pad1 = container.Resolve<AbstractPad>();
AbstractPad pad2 = container.Resolve<AbstractPad>();
Console.WriteLine(object.ReferenceEquals(pad1, pad2));
<p><strong>线程单例</strong>:同一个线程就只有一个实例,不同线程就是不同实例</p>
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)}");
<p>//ExternallyControlledLifetimeManager 外部可开释单例<br />//PerResolveLifetimeManager循环引用</p>
<p> </p>
<p><strong> 自己写的容器内里,加上生命周期:</strong></p>
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;
Type type = BingleContainerDictionary.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;
}
else
{
result = (T)this.CreateObject(type);
this.TypeObjectDictionary = 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;
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;
}
else
{
para = this.CreateObject(targetType);
this.TypeObjectDictionary = 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)}");
<p> </p>
<p> 容器依赖细节?如果不想依赖细节,又想创建对象,反射+设置文件:</p>
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();
<p>设置文件:</p>
<div align="center"></div><div align="center"></div>
<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
<p> </p><br><br/><br/><br/><br/><br/>来源:<a href="https://www.cnblogs.com/taotaozhuanyong/p/11562082.html" target="_blank">https://www.cnblogs.com/taotaozhuanyong/p/11562082.html</a>
页:
[1]