实现一个简易的IOC容器
先说一下简单思路,参考ServiceCollection,需要一个注册方法跟获取实例方法,同时支持构造函数注入。那么只需要一个地方存储注册接口跟该接口的继承类,以及根据类的构造函数去实例化一个对象出来。
创建一个.net core控制台程序,新建一个Container类。
创建一个静态字典存储类以及对应的type,这就是存储注册接口的地方
static Dictionary<string, Type> typeDic = new Dictionary<string, Type>();
然后就是实例化对象方法
/// <summary> /// 根据类型实例化对象 /// </summary> /// <param name="type"></param> /// <returns></returns> public T GetService<T>() { var type = typeof(T); var targetType = typeDic[type.FullName]; return (T)Activator.CreateInstance(targetType); }
很简单的一个方法,也有很明显的缺陷,不过现在已经可以根据注册的接口来实例化一个类。
最明显的一个问题是,没有根据构造函数来实例化类,下面来进行改进:
/// <summary> /// 根据类型实例化对象 /// </summary> /// <param name="type"></param> /// <returns></returns> public object CreateInstance(Type type) { object result = new object(); var targetType = typeDic[type.FullName]; var ctor = targetType.GetConstructors().OrderByDescending(c => c.GetParameters().Length).FirstOrDefault(); var paraList = new List<object>(); if (ctor != null) { foreach (var para in ctor.GetParameters()) { var paraType = para.ParameterType; var paraInstance = CreateInstance(paraType); paraList.Add(paraInstance); } } try { result = Activator.CreateInstance(targetType, paraList.ToArray()); } catch (Exception ex) { Console.WriteLine(ex.Message); } return result; }
把容器实例化对象的方法独立出来,上面的方法做了两个改进:
- 默认选取最多参数的构造函数,这也是ServiceCollection的策略
- 递归构造函数里面的每个参数,为每个参数都进行实例化
再添加一个方法调用该方法给外部使用
/// <summary> /// 获取实例 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public T GetService<T>() { return (T)CreateInstance(typeof(T)); }
到这里就可以进行测试了,新建一个ISql接口,创建一个查询方法
namespace ISql { public interface ISqlHelpr { void Query(); } }
分别创建两个类继承ISql
using System; using ISql; namespace MySqlTest { public class MySqlHelpr : ISqlHelpr { public void Query() { Console.WriteLine("使用Mysql查询"); } } }
using System; using ISql; namespace MySqlServerTest { public class SqlServerHelper : ISqlHelpr { public void Query() { Console.WriteLine("使用SqlServer查询"); } } }
返回控制台,新建一个容器,注册,获取实例,进行测试:
可以看到注册不同的类就实例化了对应的对象实例
下面再创建一个testClass类继承Itest接口,在MySqlHelper类中调用,展示构造函数注入
public interface Itest { public void consoleTest(); } public class testClass : Itest { public void consoleTest() { Console.WriteLine("调用consoleTest"); } }
修改MySqlHelpr
public class MySqlHelpr : ISqlHelpr { private readonly Itest _testClass; public MySqlHelpr(Itest testClass) { _testClass = testClass; } public void Query() { _testClass.consoleTest(); Console.WriteLine("使用Mysql查询"); } }
回到控制台,注册testClass,就可以看到结果
done