C# 实现IOC 设计原则和简单封装
IOC设计原则
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
实现规则
依赖倒置原则(DIP): 设计模式的六大原则之一。
依赖注入(DI): IOC的实现方式之一。
IOC容器: 依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。
依赖倒置原则(DIP)
概念:高层模块不依赖低层次模块的细节,高层次就是不依赖细节而是依赖抽象(不依赖具体的类,而是依赖于接口)
伪代码:
interface IModuleBase
{
void Init();
}
public class ModuleA : IModuleBase
{
public void Init()
{
Console.WriteLine("ModuleA Init");
}
}
public class ModuleB :IModuleBase
{
public void Init()
{
Console.WriteLine("ModuleB Init");
}
}
class Program
{
static void Main(string[] args)
{
IModuleBase aTest = new ModuleA();
IModuleBase bTest = new ModuleB();
aTest.Init();
bTest.Init();
}
}
输出结果为:
ModuleA Init
ModuleB Init
依赖注入(DI)
控制反转实现的一种方式,就是就是将依赖对象的创建和绑定转移到被依赖对象类的外部来实。
依赖注入有多种实现方式:
- 构造函数注入
public class ModuleManager
{
private IModuleBase module;
public ModuleManager(IModuleBase module)
{
this.module = module;
}
}
class Program
{
static void Main(string[] args)
{
IModuleBase aTest = new ModuleA();
ModuleManager manager = new ModuleManager(aTest);
}
}
- 属性注入
public class ModuleManager
{
private IModuleBase module;
public ModuleManager()
{
}
public IModuleBase Module { get => module; set => module = value; }
public void Init()
{
module.Init();
}
}
//调用测试
static void Main(string[] args)
{
IModuleBase aTest = new ModuleA();
ModuleManager manager = new ModuleManager();
manager.Module = aTest;
manager.Init();
}
- 接口注入
public interface IManager
{
void SetModue(IModuleBase module);
}
public class ModuleManager: IManager
{
private IModuleBase module;
public void Init()
{
module.Init();
}
public void SetModue(IModuleBase module)
{
this.module = module;
}
}
static void Main(string[] args)
{
IModuleBase aTest = new ModuleA();
ModuleManager manager = new ModuleManager();
manager.SetModue(aTest);
manager.Init();
}
IOC容器
class IocContainer
{
Dictionary<Type, Type> iocMap = new Dictionary<Type, Type>();
/// <summary>
/// 手动注册
/// </summary>
/// <typeparam name="TypeInterface"></typeparam>
/// <typeparam name="InterfaceClass"></typeparam>
public void Register<TypeInterface, InterfaceClass>()
{
if (iocMap.ContainsKey(typeof(TypeInterface)))
{
throw new Exception(string.Format("The interface {0} have be registered to Container", typeof(TypeInterface).FullName));
}
else
{
iocMap.Add(typeof(TypeInterface), typeof(InterfaceClass));
}
}
public T Resolve<T>()
{
return (T)Resolve(typeof(T));
}
public object Resolve(Type TypeInterface)
{
if (!iocMap.ContainsKey(TypeInterface))
{
throw new Exception(string.Format("The interface {0} not be registered to Container", TypeInterface.FullName));
}
Type InterfaceClass = iocMap[TypeInterface];
ConstructorInfo conInfo = InterfaceClass.GetConstructors().First();
List<ParameterInfo> paramsInfoList = conInfo.GetParameters().ToList();
List<object> interfaceClassParams = new List<object>();
foreach (var param in paramsInfoList)
{
Type temp = param.ParameterType;
object result = Resolve(temp);
interfaceClassParams.Add(result);
}
object resultObject = conInfo.Invoke(interfaceClassParams.ToArray());
return resultObject;
}
}
上面是一个简单的IOC容器,下面是我想通过构造函数以配置的方式去注册容器内容,代码如下:
class IocContainer
{
Dictionary<Type, Type> iocMap = new Dictionary<Type, Type>();
public IocContainer()
{
string config = "IModuleA;IModuleB";//配置文件
Assembly asm = Assembly.GetAssembly(typeof(ModuleAttribute));
Type[] types = asm.GetExportedTypes();
Func<Attribute[], bool> IsMyAttribute = o =>
{
foreach (Attribute a in o)
{
if (a is ModuleAttribute)
return true;
}
return false;
};
Type[] typesTemp = types.Where(o =>
{
return IsMyAttribute(Attribute.GetCustomAttributes(o, true));
}).ToArray();
string[] tempArray = config.Split(';');
foreach(string item in tempArray)
{
foreach(Type typeItem in typesTemp)
{
Type inter = typeItem.GetInterfaces().ToList().Find(o => o.Name.Equals(item));
if(inter != null)
{
iocMap.Add(inter,typeItem);
}
}
}
//Register<IModuleA, ModuleA>();
//Register<IModuleB, ModuleB>();
}
/// <summary>
/// 手动注册
/// </summary>
/// <typeparam name="TypeInterface"></typeparam>
/// <typeparam name="InterfaceClass"></typeparam>
public void Register<TypeInterface, InterfaceClass>()
{
if (iocMap.ContainsKey(typeof(TypeInterface)))
{
throw new Exception(string.Format("The interface {0} have be registered to Container", typeof(TypeInterface).FullName));
}
else
{
iocMap.Add(typeof(TypeInterface), typeof(InterfaceClass));
}
}
public T Resolve<T>()
{
return (T)Resolve(typeof(T));
}
public object Resolve(Type TypeInterface)
{
if (!iocMap.ContainsKey(TypeInterface))
{
throw new Exception(string.Format("The interface {0} not be registered to Container", TypeInterface.FullName));
}
Type InterfaceClass = iocMap[TypeInterface];
ConstructorInfo conInfo = InterfaceClass.GetConstructors().First();
List<ParameterInfo> paramsInfoList = conInfo.GetParameters().ToList();
List<object> interfaceClassParams = new List<object>();
foreach (var param in paramsInfoList)
{
Type temp = param.ParameterType;
object result = Resolve(temp);
interfaceClassParams.Add(result);
}
object resultObject = conInfo.Invoke(interfaceClassParams.ToArray());
return resultObject;
}
}
在IocContainer中我通过反射去的ModuleAttribute标注的类,去将器注册到容器内,测试如下:
static void Main(string[] args)
{
//IOC测试
IocContainer container = new IocContainer();
container.Resolve<IModuleA>().FunA();
container.Resolve<IModuleB>().FunB();
}
输出结果:
ModuleA Init
ModuleB Init
参考代码下载