using BLLExtention;
using DAL;
using IBLL;
using IDAL;
using Microsoft.Practices.Unity.Configuration;
using MyContainer;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Unity;
using Unity.Lifetime;
namespace MyIOC
{
class Program
{
static void Main(string[] args)
{
//分层UI——BLL(业务逻辑)——DAL(数据访问):划分边界,独立演化;职责清晰,方便分工合作;提高代码复用
//依赖倒置原则DIP:系统架构时,高层模块不应该依赖低层模块,两者通过抽象来依赖。依赖抽象而不应该依赖细节
//控制反转:把上端对下端的依赖转移到第三方容器(工厂+配置+反射)中去
//DI依赖注入:创建对象时的依赖的另外对象,可以通过自动初始化并传入(比如构造A时需要传入B,实现B自动构造并传入A的过程叫做 依赖注入)
// 依赖注入的三种方式:构造函数注入--属性注入--方法注入(按三者执行循序依次注入)
// 使用最多的是构造函数注入:默认找参数最多的构造函数,而且可以省略特性,这样被注入对象可以省略对容器的依赖
//IOC是最终目标,DI是实现这个目标的手段
{
抽象+反射+配置 把实例化对象的细节放入工厂,工厂再通过配置实现 但是如果创建对象的时候有依赖,还是得先把依赖创建,手动可以创建,但是又更好的框架Unity
//IPlant pine = (IPlant)Fctory.CreatePlant();
//pine.Photosynthesis();
}
{
//Unity实现控制反转
//1.添加nuget包
//2.容器三部曲
//3.注意各个项目的Unity版本一致,可以从解决方案菜单统一管理
{
使用容器
//IUnityContainer container = new UnityContainer();//1实例化容器
container.RegisterType<IPlant, Pine>();//2.注册类型
//container.RegisterInstance<IPlant>(new Pine());//通过子类实例来注册
container.RegisterType<IPlant, Willow>();//再次用相同接口/父类注册会覆盖之前注册的
//container.RegisterType<AbstractTree, Cypress>();//也可以通过抽象类注册对象
// //container.RegisterType<Cypress, ChineseJuniper>();//也可以通过父类注册对象 但是父类不能在之前被注册(不能出现在泛型括号的右边),会导致获取对象取到孙子对象
//IPlant pine = container.Resolve<IPlant>();//3.获取实例
//AbstractTree cypress = container.Resolve<AbstractTree>();
//Cypress chineseJuniper = container.Resolve<Cypress>();
}
{
带依赖的注册 实现依赖注入
//IUnityContainer container = new UnityContainer();//1实例化容器
//container.RegisterType<AbstractTree, Poplar>();
//container.RegisterType<IBranch, Branch>();
//container.RegisterType<ILeaves, Leaves>();
//AbstractTree poplar = container.Resolve<AbstractTree>();//默认找无参构造函数,可以通过特性来指定构造函数
poplar.Photosynthesis();
}
{
#region 自己实现容器
自己实现容器
//ISanSanContainer container = new SanSanContainer();//1实例化容器
//container.RegisterType<AbstractTree, Poplar>(LifeTime.Singleton);
container.RegisterType<IBranch, Branch>();
container.RegisterType<ILeaves, Leaves>();
//AbstractTree poplar = container.Resolve<AbstractTree>();//默认找无参构造函数,可以通过特性来指定构造函数
//AbstractTree poplar1 = null;
//AbstractTree poplar2 = null;
//AbstractTree poplar3 = null;
//Action action1 = new Action(() =>
//{
// poplar1 = container.Resolve<AbstractTree>();
// Console.WriteLine($"poplar1线程ID{Thread.CurrentThread.ManagedThreadId}");
//});
//var rst1 = action1.BeginInvoke(null, null);
//Action action2 = new Action(() =>
//{
// poplar2 = container.Resolve<AbstractTree>();
// Console.WriteLine($"poplar2线程ID{Thread.CurrentThread.ManagedThreadId}");
//});
//var rst2 = action2.BeginInvoke(t =>
//{
// poplar3 = container.Resolve<AbstractTree>();
// Console.WriteLine($"poplar3线程ID{Thread.CurrentThread.ManagedThreadId}");
// Console.WriteLine($"object.ReferenceEquals(poplar2, poplar3)={object.ReferenceEquals(poplar2, poplar3)}");
//}, null);
//action1.EndInvoke(rst1);
//action2.EndInvoke(rst2);
//Console.WriteLine($"object.ReferenceEquals(poplar1, poplar2)={object.ReferenceEquals(poplar1, poplar2)}");
#endregion
#region 基于配置实现容器
//1.未做配置中带别命的,思路:存类型的字典的键值不能是父类Type了,得把别名信息也加上
// 创建时根据别命和父类Type共同查找该实例化哪个子类
//2.指定参数值未作 思路:获取了构造参数的参数值,来和配置中的比对
// 如果就是配置中的参数,值类型直接赋值,引用类型按照配置的类型去实例化
//3.泛型 type.GetGenericTypeDefinition()获取原始泛型类型
// 获取泛型类型typeof(IBLL.IGeneric<>);
Type ty1 = typeof(IGeneric<string>);
Type ty2 = typeof(IBLL.IGeneric<>);
bool iseq = ty1.GetGenericTypeDefinition() == ty2;
ISanSanContainer container = new SanSanContainer();
string jsonPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"CfgFiles\SanSanContainer.json");
SanSanConfigurationSection sanSanConfig = new SanSanConfigurationSection(jsonPath);
sanSanConfig.Configure(container, "testContainer1");
AbstractTree poplar = container.Resolve<AbstractTree>();
poplar.Photosynthesis();
IGeneric<string> generic = container.Resolve<IGeneric<string>>();
generic.Show();
#endregion
}
{
#region 生命周期
//可以做一些扩展,生命周期管理
//1.瞬时生命周期:每次都是构造一个新的,每次生成一个新对象
//IUnityContainer container = new UnityContainer();
瞬时生命周期:
//container.RegisterType<AbstractTree, Poplar>();//默认就是瞬时
//container.RegisterType<AbstractTree, Poplar>(new TransientLifetimeManager());//瞬时
//2.全局单例:全局只构造这一个对象实例
//非强制性单例,只有通过容器获取才是单例;项目中一般都通过这种方式生成单例,避免自己写
//container.RegisterType<AbstractTree, Poplar>(new SingletonLifetimeManager());
//3.线程单例:同一个线程是同一个实例,不同线程不同
//container.RegisterType<AbstractTree, Poplar>(new PerThreadLifetimeManager());
//AbstractTree poplar1 = null;
//AbstractTree poplar2 = null;
//AbstractTree poplar3 = null;
//Action action1 = new Action(() =>
//{
// poplar1 = container.Resolve<AbstractTree>();
// Console.WriteLine($"poplar1线程ID{Thread.CurrentThread.ManagedThreadId}");
//});
//var rst1 = action1.BeginInvoke(null, null);
//Action action2 = new Action(() =>
//{
// poplar2 = container.Resolve<AbstractTree>();
// Console.WriteLine($"poplar2线程ID{Thread.CurrentThread.ManagedThreadId}");
//});
//var rst2 = action2.BeginInvoke(t =>
//{
// poplar3 = container.Resolve<AbstractTree>();
// Console.WriteLine($"poplar3线程ID{Thread.CurrentThread.ManagedThreadId}");
// Console.WriteLine($"object.ReferenceEquals(poplar2, poplar3)={object.ReferenceEquals(poplar2, poplar3)}");
//}, null);
//action1.EndInvoke(rst1);
//action2.EndInvoke(rst2);
//Console.WriteLine($"object.ReferenceEquals(poplar1, poplar2)={object.ReferenceEquals(poplar1, poplar2)}");
//4.分级容器单例,每个子容器构造的实例是同一个
//var childContainer = container.CreateChildContainer();
//外部可释放单例
//循环引用
#endregion
}
{
#region Unity实现AOP+IOC
//上面的容器注册类型时还是会依赖细节,要避免依赖的话,反射+配置
//1.一个接口多个不同类型实例,配置中加别命
//2.构造时需要传入具体值,配置中构造函数的参数值写死(写死好像没办法),param配置
// 需要灵活,就不能在构造参数时传入具体值,可以实现在类中写个属性,构造参数使用该属性替换参数,实例化后再对该属性赋值,实现可变
//3.泛型注册 配置类型名称+`1
//容易一般全局只有一个,初始化时创建一个容器供全局使用
//ABP??
//需要AOP时配置中增加相应节点,一定要引用Unity.Interception.Configuration类库,否则报读配置错误,
#region 读配置固定写法,不用关心
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();//
fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"CfgFiles\Unity.config");
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
#endregion
//声明容器
IUnityContainer container = new UnityContainer();//
//这个是配置中容器的名字<container>标签
configSection.Configure(container, "testContainer1");
AbstractTree poplar = container.Resolve<AbstractTree>();
poplar.Photosynthesis();
//传入别名,实现相同父类注册不同子类
AbstractTree cypress = container.Resolve<AbstractTree>("Cypress");
cypress.Photosynthesis();
IGeneric<string> generic = container.Resolve<IGeneric<string>>();
generic.Show();
#endregion
}
}
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity"
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Unity.Configuration" />
</configSections>
<unity>
<!--type前面是完整类型名称,后面是Dll名称-->
<sectionExtension
type ="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension,
Unity.Interception.Configuration"/>
<containers>
<!--可以添加多个container来实现多个接口的AOP-->
<!--容器名称,代码中是要用这个名称的-->
<container name ="testContainer1">
<extension type ="Interception"/>
<!--容器支持AOP,得加此节点-->
<!--前面的写法都是固定的-->
<!--type前面是接口名称,后面是dll名称;mapTo是要映射的类的名称,后面是dll名称-->
<register type ="BLLExtention.AbstractTree,BLLExtention" mapTo="BLLExtention.Poplar,BLLExtention"/>
<!--同一个父对象需要注册多个子类,加个别命-->
<register type ="BLLExtention.AbstractTree,BLLExtention" mapTo="BLLExtention.Cypress,BLLExtention" name ="Cypress">
<!--指定构造函数中的参数-->
<constructor>
<param name="leaves" type="IDAL.ILeaves,IDAL"/>
<param name="i" type="System.Int32" value="3"/>
</constructor>
</register>
<register type ="IDAL.IBranch,IDAL" mapTo="DAL.Branch,DAL"/>
<register type ="IDAL.ILeaves,IDAL" mapTo="BLLExtention.Leaves,BLLExtention"/>
<register type ="IBLL.IGeneric`1,IBLL" mapTo="BLL.MyGeneric`1,BLL">
<!--IOC+AOP-->
<interceptor type ="InterfaceInterceptor"/>
<interceptionBehavior type="MyAop.UnityWay.LogBeforeBehavior,MyAop"/>
<interceptionBehavior type="MyAop.UnityWay.CachingBehavior,MyAop"/>
<interceptionBehavior type="MyAop.UnityWay.ExceptionLoggingBehavior,MyAop"/>
<interceptionBehavior type="MyAop.UnityWay.LogAfterBehavior,MyAop"/>
<interceptionBehavior type="MyAop.UnityWay.MonitorBehavior,MyAop"/>
</register>
</container>
<!--<container name ="testContainer">
<extension type ="Interception"/>
-->
<!--前面的写法都是固定的-->
<!--
-->
<!--type前面是接口名称,后面是dll名称;mapTo是要映射的类的名称,后面是dll名称-->
<!--
<register type ="MyAop.UnityWay.IUserProcessor,MyAop" mapTo="MyAop.UnityWay.UserProcessor,MyAop">
-->
<!--指定扩展类型是基于接口的扩展(还有基于方法的、基于类的)-->
<!--
<interceptor type ="InterfaceInterceptor"/>
<interceptionBehavior type="MyAop.UnityWay.LogBeforeBehavior,MyAop"/>
<interceptionBehavior type="MyAop.UnityWay.ParameterCheckBehavior,MyAop"/>
<interceptionBehavior type="MyAop.UnityWay.CachingBehavior,MyAop"/>
<interceptionBehavior type="MyAop.UnityWay.ExceptionLoggingBehavior,MyAop"/>
<interceptionBehavior type="MyAop.UnityWay.LogAfterBehavior,MyAop"/>
<interceptionBehavior type="MyAop.UnityWay.MonitorBehavior,MyAop"/>
</register>
</container>-->
</containers>
</unity>
</configuration>
实现容器:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyContainer
{
public interface ISanSanContainer
{
Dictionary<Type, RegisterInfo> DicRegisterType { set; get; }
void RegisterType<TFrom, TTo>(LifeTime lifeTime = LifeTime.Transient) where TTo : TFrom;
T Resolve<T>();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks;
namespace MyContainer
{
public class SanSanContainer : ISanSanContainer
{
public Dictionary<Type, RegisterInfo> DicRegisterType { set; get; } = new Dictionary<Type, RegisterInfo>();
private Dictionary<Type, object> DicSingletonVal = new Dictionary<Type, object>();
private static readonly object ObjLock = new object();
public void RegisterType<TFrom, TTo>(LifeTime lifeTime = LifeTime.Transient) where TTo : TFrom
{
if (DicRegisterType.Keys.Contains(typeof(TFrom)))
{
DicRegisterType[typeof(TFrom)] = new RegisterInfo()
{
RegisterType = typeof(TTo),
RegisterLifeTime = lifeTime
};
}
else
{
DicRegisterType.Add(typeof(TFrom), new RegisterInfo()
{
RegisterType = typeof(TTo),
RegisterLifeTime = lifeTime
});
}
}
public T Resolve<T>()
{
try
{
T instance = (T)InjectionPara(typeof(T));
return instance;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return default(T);
}
}
private object InjectionPara(Type tFrom)
{
object objRst = null;
Type type = tFrom;
LifeTime lifeTime = LifeTime.Transient;
if (type.IsGenericType)//判断是否是泛型
{
Type genericParent = type.GetGenericTypeDefinition();
if (DicRegisterType.ContainsKey(genericParent))
{
Type[] types = type.GenericTypeArguments;
type = DicRegisterType[genericParent].RegisterType.MakeGenericType(types); ;
}
}
else
{
if (DicRegisterType.ContainsKey(tFrom))
{
type = DicRegisterType[tFrom].RegisterType;
lifeTime = DicRegisterType[tFrom].RegisterLifeTime;
}
}
if (lifeTime.Equals(LifeTime.Singleton))
{
if (DicSingletonVal.ContainsKey(type))
return DicSingletonVal[type];
}
else if (lifeTime.Equals(LifeTime.PerThread))
{
//线程槽
object oValue = CallContext.GetData(type.FullName);
if (oValue != null)
{
return oValue;
}
}
#region 构造函数注入
//构造函数注入
ConstructorInfo[] ctorArr = type.GetConstructors()
.Where(t => t.IsDefined(typeof(SanSanInjectionConstructorAttribute)))
.OrderByDescending(t => t.GetParameters().Count()).ToArray();
ConstructorInfo ctor = null;
if (ctorArr == null || ctorArr.Count() <= 0)
{
ctor = type.GetConstructors().OrderByDescending(t => t.GetParameters().Count()).First();
//return Activator.CreateInstance(type);
}
else
{
ctor = ctorArr.First();
}
List<object> paraObjList = new List<object>();
foreach (var parameter in ctor.GetParameters())
{
Type paraType = parameter.ParameterType;
object paraObj = InjectionPara(paraType);
paraObjList.Add(paraObj);
}
if (paraObjList.Count() > 0)
{
objRst = Activator.CreateInstance(type, paraObjList.ToArray());
}
else
{
objRst = Activator.CreateInstance(type);
}
#endregion
#region 属性注入
//属性注入
PropertyInfo[] propertyArr = type.GetProperties()
.Where(t => t.IsDefined(typeof(SanSanDependencyAttribute))).ToArray();
if (propertyArr != null && propertyArr.Count() > 0)
{
foreach (PropertyInfo property in propertyArr)
{
property.SetValue(objRst, InjectionPara(property.PropertyType));
}
}
#endregion
#region 方法注入
//方法注入
MethodInfo[] methodArr = type.GetMethods()
.Where(t => t.IsDefined(typeof(SanSanInjectionMethodAttribute))).ToArray();
if (methodArr != null && methodArr.Count() > 0)
{
foreach (MethodInfo method in methodArr)
{
List<object> paraObjListMethod = new List<object>();
foreach (var parameter in method.GetParameters())
{
Type paraType = parameter.ParameterType;
object paraObj = InjectionPara(paraType);
paraObjListMethod.Add(paraObj);
}
method.Invoke(objRst, paraObjListMethod.ToArray());
}
}
#endregion
if (lifeTime.Equals(LifeTime.Singleton))
{
lock (ObjLock)
{
if (!DicSingletonVal.ContainsKey(type))
DicSingletonVal.Add(type, objRst);
else
return DicSingletonVal[type];
}
}
else if (lifeTime.Equals(LifeTime.PerThread))
{
//线程槽
CallContext.SetData(type.FullName, objRst);
}
return objRst;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyContainer
{
public class RegisterInfo
{
public Type RegisterType { set; get; }
public LifeTime RegisterLifeTime { set; get; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyContainer
{
public enum LifeTime
{
/// <summary>
/// 瞬时
/// </summary>
Transient,
/// <summary>
/// 全局单例
/// </summary>
Singleton,
/// <summary>
/// 线程单例
/// </summary>
PerThread,
}
}
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace MyContainer
{
public class SanSanConfigurationSection
{
private string JsonPath { set; get; }
public SanSanConfigurationSection(string path)
{
JsonPath = path;
}
public void Configure(ISanSanContainer container, string containerName)
{
ContainerConfigMode containerConfigMode = JsonConfigToContainerObj();
if (containerConfigMode == null)
throw new Exception("未找到配置文件");
var containerMode = containerConfigMode.listContainer.Where(t => t.ContainerName.Equals(containerName)).FirstOrDefault();
if (containerMode == null)
throw new Exception("未找到对应容器");
containerMode.listRegister.ForEach(t =>
{
Type typeParent = GetTypeFromConfig(t.Type);
Type typeChild = GetTypeFromConfig(t.MapTo);
if (!container.DicRegisterType.ContainsKey(typeParent))
container.DicRegisterType.Add(typeParent, new RegisterInfo
{
RegisterLifeTime = LifeTime.Transient,
RegisterType = typeChild
});
});
}
private Type GetTypeFromConfig(string path)
{
string[] arrParent = path.Split(',');
Assembly assembly = Assembly.Load(arrParent[1]);
Type typeParent = assembly.GetType(arrParent[0]);
return typeParent;
}
private ContainerConfigMode JsonConfigToContainerObj()
{
if (!File.Exists(JsonPath))
{
return null;
}
string strJson = File.ReadAllText(JsonPath);
return JsonConvert.DeserializeObject<ContainerConfigMode>(strJson);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyContainer
{
internal class ContainerConfigMode
{
public List<ContainerMode> listContainer { set; get; }
}
internal class ContainerMode
{
public string ContainerName { set; get; }
public List<Register> listRegister { set; get; }
}
internal class Register
{
public string Type { set; get; }
public string MapTo { set; get; }
}
}
特性标记注入方式
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyContainer
{
[AttributeUsage(AttributeTargets.Constructor)]
public class SanSanInjectionConstructorAttribute : Attribute
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyContainer
{
[AttributeUsage(AttributeTargets.Method)]
public class SanSanInjectionMethodAttribute : Attribute
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyContainer
{
[AttributeUsage(AttributeTargets.Property)]
public class SanSanDependencyAttribute : Attribute
{
}
}
配置
{
"listContainer": [
{
"ContainerName": "testContainer1",
"listRegister": [
{
"MapTo": "BLLExtention.Poplar,BLLExtention",
"Type": "BLLExtention.AbstractTree,BLLExtention"
},
{
"MapTo": "BLLExtention.Cypress,BLLExtention",
"Type": "BLLExtention.AbstractTree,BLLExtention"
},
{
"MapTo": "DAL.Branch,DAL",
"Type": "IDAL.IBranch,IDAL"
},
{
"MapTo": "BLLExtention.Leaves,BLLExtention",
"Type": "IDAL.ILeaves,IDAL"
},
{
"MapTo": "BLL.MyGeneric`1,BLL",
"Type": "IBLL.IGeneric`1,IBLL"
}
]
}
]
}