Inversion of Control / Dependency Injection and conversion operators
我有一个用户模型类,它被许多MVC应用程序使用,我正试图将其转换为使用IOC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class UserModel { public string Login { get; set; } [DisplayName("Display Name")] public string DisplayName { get; set; } public static explicit operator UserModel(string userLogin) { IKernel IoC; // Where do I get this from? var ActiveDirRepo = IoC.Get<IActiveDirectoryRepository>(); var User = ActiveDirRepo.FindById<ActiveDirectoryUser>(userLogin.ToUpper()); return new UserModel() { Login = userLogin, DisplayName = User == null ? userLogin.ToUpper() : User.Name }; } } |
它有一个从
我现在遇到的问题是,如何引用我的IOC容器(
我不能把它从外部注入到EDCOX1 1中,因为操作符就是创建它的东西。
从思想上讲,IOC容器应该只存在于应用程序的复合根中。考虑到这一点,需要弄清楚类的依赖性,并通过构造函数注入它们(如果您不能进行构造函数DI,那么许多IOC容器都会提供其他注入方法)。
在这里,您需要访问
直接:使用服务定位器模式。使用服务定位器获取EDCOX1 OR 0的实例。这将很好地直接适应当前的实现(将内核行交换到服务定位器)。但是,这种模式也有一些缺陷;最重要的是,你将EDCOX1的0源代码内化,这将使单元测试变得不那么有效。
传统:让你的
UserModel 创建者进入一个工厂,通过它的建设者接受IActiveDirectoryRepository 。然后,工厂创建的任何UserModel 使用提供的IActiveDirectoryRepository 。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public sealed class UserFactory
{
private readonly IActiveDirecotryRepository repository;
public UserFactory(IActiveDirectoryRepository repository)
{
this.repository = repository;
}
public UserModel CreateNewUser(string userLogin)
{
var User = repository.FindById<ActiveDirectoryUser>(userLogin.ToUpper());
return new UserModel()
{
Login = userLogin,
DisplayName = User == null ? userLogin.ToUpper() : User.Name
}
}
}花式:在
IActiveDirectoryRepository 上创建一个闭包,并将创建者作为一级函数传递。1
2
3
4
5
6
7
8
9
10
11
12static Func<string, UserModel> CreateFactory(IActiveDirectoryRepository repository)
{
return (userLogin) =>
{
var User = repository.FindById<ActiveDirectoryUser>(userLogin.ToUpper());
return new UserModel()
{
Login = userLogin,
DisplayName = User == null ? userLogin.ToUpper() : User.Name
}
}
}
这种转换应该很简单,不需要外部依赖。如果需要注入某种依赖项,那么忘记了转换,就没有解决方案。
足够简单,将ikernel传递到构建方法:
1 2 3 4 5 6 7 8 9 10 11 12 | public static UserModel Build(string userLogin, IKernel IoC) { var ActiveDirRepo = IoC.Get<IActiveDirectoryRepository>(); var User = ActiveDirRepo.FindById<ActiveDirectoryUser>(userLogin.ToUpper()); return new UserModel() { Login = userLogin, DisplayName = User == null ? userLogin.ToUpper() : User.Name }; } |
然后,您可以问自己,这个方法是否属于ikernel接口:
1 2 3 4 | interface IKernel { UserModel Build(string userLogin); } |
国际奥委会没有什么魔力。有时,您仍然需要一个起点,从该起点可以访问应用程序的IOC容器,如下所示:
1 | var ioc = Application.Instance.Container.Get<IActiveDirectoryRepository>(); |
您不需要从任何地方访问IOC容器,因为通过容器创建的对象已经注入了它们的依赖项,但至少一些根对象需要获得对容器的访问权。
如果ninject不提供实现,则可以使用服务定位器模式表单microsoft.practices.servicelocation i。如果不这样做,就直接开始实施。
不管您能用这段代码做什么,我强烈建议您不要像以前那样实现显式转换运算符。这是一种不好的做法。