我的任务是建立代码模式,以用于我们正在构建的新应用程序。早期的决定是使用Prism& amp ;;来构建我们的应用程序和库。 MEF旨在简化测试和跨应用程序重用功能。
随着我们的代码库不断增长,我遇到了一个问题。 假设我们有一些需要访问某个系统的基础库 - 让我们说一个用户管理系统:
public interface IUserManagementSystem
{
IUser AuthenticateUser(string username, string password);
}
// ...
public class SomeClass
{
[ImportingConstructor]
public SomeClass(IUserManagementSystem userSystem){ }
}
我们现在可以使用ServiceLocator创建SomeClass类型的对象,但仅限于已注册IUserManagementSystem的实现。没有办法知道(在编译时)创建是成功还是失败,需要哪些实现或其他关键信息。
如果我们在库中使用ServiceLocator,这个问题会变得更加复杂。
查找现在隐藏的依赖项已成为比遗留应用程序中的硬编码依赖项更大的问题。 IoC和依赖注入模式并不新颖,一旦我们将这项工作从编译器中删除,我们应该如何管理依赖项?我们应该完全避免在库代码中使用ServiceLocator(或其他IoC容器)吗?
编辑:我特别想知道如何处理横切关注点(例如日志记录,通信和配置)。我已经看到了建立CCC项目的一些建议(大概是大量使用单身人士)。在其他情况下(Is the dependency injection a cross-cutting concern?),建议在整个库中使用DI框架,以回溯追踪依赖关系的原始问题。
Dependency Inject (DI) "friendly" library有点相关,因为它解释了如何以可以与DI框架一起使用或不与DI框架一起使用的方式构造代码,但它没有解决使用DI是否有意义的问题。 在库中或如何确定给定库所需的依赖项。那里标记的答案提供了关于与DI框架交互的可靠建筑建议,但它没有解决我的问题。
答案 0 :(得分:4)
您不应该在核心库中使用ServiceLocator或任何其他特定于DI框架的部分。这会将您的代码耦合到特定的DI框架,并使得任何消费您的库的人都必须将DI框架作为其产品的依赖项添加。相反,使用构造函数注入和各种技术mentioned by Mark Seeman in his excellent answer here。
然后,为了帮助您的库的用户更容易地进行自举,您可以提供单独的DI-Container特定库以及一些基本实用程序类,这些类可以处理您期望人们使用的大多数标准DI绑定,所以在很多情况下,他们可以开始使用一行代码。
在使用DI框架时,在运行时之前缺少依赖关系的问题是常见问题。唯一真正的方法是使用"穷人的DI",你有一个实际定义每种类型的对象如何构造的类,所以你得到一个编译时错误,如果引入了您尚未处理的依赖关系。
但是,您通常可以通过尽可能早地在运行时中检查事物来缓解此问题。例如,SimpleInjector有一个Validate()方法,您可以在设置完所有绑定后调用它,如果它可以告诉它不知道如何为任何绑定构造依赖关系,它会抛出异常。已注册的类型。我还想在我的测试套件中添加一个简单的集成测试来设置所有绑定,然后尝试构建我的应用程序中的所有顶级类型(例如Web API控制器),如果它不能,则会失败这样做。