控制反转/依赖注入和转换运算符
本文关键字:转换 运算符 注入 依赖 控制 | 更新日期: 2023-09-27 18:33:14
我有一个 UserModel 类,我正在尝试将其转换为使用 IoC:
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
};
}
}
它有一个从 string
到 UserModel
的显式转换运算符。以前我只是new
编辑了一个ActiveDirectoryRepository
并使用它,但我想开始使用 IoC/DI。
我现在遇到的问题是,如何引用我的 IoC 容器 ( IKernel
(?
我无法从外部将其注入UserModel
,因为操作员是创建它的人。
这种转换应该是简单的,这不应该需要外部依赖。如果您需要注入某种依赖项,那么忘记了转换,没有解决方案。
很简单,将 IKernel 传递给构建方法:
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 接口是否有意义:
interface IKernel
{
UserModel Build(string userLogin);
}
IoC 中没有魔法。有时你仍然需要一个起点,从中可以访问应用程序的 IoC 容器,如下所示:
var ioc = Application.Instance.Container.Get<IActiveDirectoryRepository>();
不需要从任何地方访问 IoC 容器,因为通过容器创建的对象已经注入了其依赖项,但至少某些根对象需要访问容器。
意识形态上讲,IoC 容器应仅存在于应用程序的复合根中。考虑到这一点,这是一个弄清楚你的类依赖项并通过构造函数注入它们的问题(如果你不能做构造函数 DI,那么许多 IoC 容器提供了替代的注入方法(。
在这里,您需要访问IActiveDirectoryRepository
才能创建用户模型。但是,您的创建方法 explicit operator UserModel
是一种静态方法,无法访问实例变量。不幸的是,这限制了您使用依赖注入来利用 IoC 的能力,因此这里有一些想法:
简单:使用服务定位器模式。使用服务定位器获取
IActiveDirectoryRepository
的实例。这将直接很好地适应您当前的实现(将内核行交换到服务定位器(。但是,这种模式有缺点;最值得注意的是,您正在内化IActiveDirectoryRepository
源,这将使单元测试效率降低。传统:将
UserModel
创建者变成一个通过构造函数接受IActiveDirectoryRepository
的工厂。然后,工厂创建的任何UserModel
都使用提供的IActiveDirectoryRepository
。public 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
上创建一个闭包,并将创建者作为一流的功能传递。static 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 } } }
您可以使用服务定位器模式表单 Microsoft.Practices.ServiceLocation 如果 ninject 不提供实现,我会感到沮丧。如果没有,则直接实施。
不管你可以用这段代码做你想做的事,我强烈建议你不要像以前那样实现显式转换运算符。这是一种不好的做法。