实现简单的构造函数注入容器
这段时间跟着Eleven老师学习收获不小,一些以前想过的可能,但是以前不知道怎么实现。
今天上班领导不在,突然想起来,便试着实现了一下诸如容器,发现 基本实现还是挺简单,基本就是反射的应用了。不废话,上代码。
首先是 容器的代码(新建一个类库封装):
public class InjectContainer { private static Dictionary<string, object> dicToInstances = new Dictionary<string, object>(); private static Dictionary<string, List<Type>> dicReturnTypeInfo = new Dictionary<string, List<Type>>(); private static object objLock = new object(); /// <summary> /// 接口注册(接口类和实现类之间的约束是接口类名称为实现类名称前面加 I) /// </summary> /// <param name="fromNameSpace">接口类命名空间</param> /// <param name="toNameSpace">实现类命名空间</param> public void Register(string fromNameSpace, string toNameSpace) { var issembly = Assembly.Load(fromNameSpace); var toAssembly = Assembly.Load(toNameSpace); var types = issembly.GetTypes(); foreach (var type in types) { if (dicToInstances.ContainsKey(type.FullName)) continue; var toType = toAssembly.GetType(string.Format("{0}.{1}", toNameSpace, type.Name.Substring(1))); var instance = Activator.CreateInstance(toType); dicToInstances.Add(type.FullName, instance); } } /// <summary> /// 获取实体(控制器每次访问都是要创建新实例的) /// </summary> /// <param name="type"></param> /// <returns></returns> public T GetInstance<T>(Type type) { List<Type> listType = new List<Type>(); if (dicReturnTypeInfo.ContainsKey(type.FullName)) { //如果有类型数据就不需要再获取一次了 listType = dicReturnTypeInfo[type.FullName]; } else { lock (objLock) { if (!dicReturnTypeInfo.ContainsKey(type.FullName)) { var ConstructorInfo = type.GetConstructors(); var parameters = ConstructorInfo[0].GetParameters(); foreach (var item in parameters) { Type fromType = item.ParameterType; listType.Add(fromType); } } } } List<object> param = new List<object>(); foreach (var pType in listType) { if (dicToInstances.ContainsKey(pType.FullName)) { param.Add(dicToInstances[pType.FullName]); } } return (T)Activator.CreateInstance(type, param.ToArray()); } }
然后建两个新的类库,分别为接口类库(IRepository)和接口实现类库(Repository)
namespace IRepository { public interface IStudentManager { string GetStudentName(); void SetStudentName(string name); } }
namespace Repository { public class StudentManager : IStudentManager { private string _Name { get; set; } public string GetStudentName() { return this._Name; } public void SetStudentName(string name) { this._Name = "Name of the student is : "+name; } } }
最后 我们建我们的 MVC 项目,这里建一个基本的 MVC 项目(项目只需引用容器类库和接口类库)。
然后在 App_Start 文件夹里(其实在哪都可以)新建一个 自定义控制器工厂 CustomControllerFactory 继承自 DefaultControllerFactory,然后重写 GetControllerInstance 方法
/// <summary> /// 自定义控制器生成类 /// </summary> public class CustomControllerFactory: DefaultControllerFactory { private InjectContainer _Container = null; public CustomControllerFactory(InjectContainer container) { this._Container = container; } protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { if (controllerType != null) return this._Container.GetInstance<IController>(controllerType); return null; } }
接着在 MVC 项目的 Global.asax 文件里注册 容器
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); //以下是容器注册 InjectContainer container = new InjectContainer(); container.Register("IRepository", "Repository"); ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory(container)); }
最后 我们在我们需要注入的 控制器 重载一个带参数的 构造函数
public class HomeController : Controller { private IStudentManager _StudentManager = null; /// <summary> /// 带接口参数的构造函数 /// </summary> /// <param name="studentManager"></param> public HomeController(IStudentManager studentManager) { this._StudentManager = studentManager; } // GET: Home public ActionResult Index() { this._StudentManager.SetStudentName("我在使用自己的注入容器,呵呵哈哈哈"); return Content(this._StudentManager.GetStudentName()); } }
整个项目结构如图:
效果: