C# 在类库中使用IoC容器

C# 在类库中使用IoC容器,c#,dependency-injection,C#,Dependency Injection,我正在使用IoC容器来注册和解析类型 我有以下项目: 项目A 甲级 -第1子类 -第2子类 项目B(类库) B类 -第3子类 -第4子类 ProjcetA正在使用ProjectB ProjectA是应用程序的入口点 ProjectA不知道子类3和子类4 我对ProjectA和ProjectB有单独的单元测试项目 既然我不想让ProjectA知道子类3和4,在类库中注册类型的正确方法是什么 我应该将IoC容器从ProjectA传递到B还是使用两个IoC容器 我的问题不是如何使库DI不可知/非DI

我正在使用IoC容器来注册和解析类型

我有以下项目:

项目A

甲级 -第1子类 -第2子类

项目B(类库)

B类 -第3子类 -第4子类

ProjcetA正在使用ProjectB

ProjectA是应用程序的入口点

ProjectA不知道子类3和子类4

我对ProjectA和ProjectB有单独的单元测试项目

既然我不想让ProjectA知道子类3和4,在类库中注册类型的正确方法是什么

我应该将IoC容器从ProjectA传递到B还是使用两个IoC容器

我的问题不是如何使库DI不可知/非DI 可用。我的问题是什么是注册儿童的最佳做法 类库中的依赖项

我的问题是在类库中注册子依赖项时的最佳实践是什么

我不想让ProjectA知道子类3和4

如果遵循DI模式,则类库将不会有“子依赖项”。相反,在启动应用程序中,依赖关系将完全(除了某些抽象库之外)简化为与组合根的1:1关系

对于
ProjectA
应用程序来说,依赖
子类3和4是的理想选择。如果
子类3和4
相互依赖或来自其他库的组件,则在使用
子类3
子类4
时会拖拽额外的依赖项

相反,将所有耦合代码放在组合根目录中,将无耦合代码放在应用层类库中。这使应用程序负责其所有依赖项

如果您有其他类型的类库,例如可重用的应用程序组件,那么可以使用一些技术来耦合它们,但仍然允许它们是可注入的。见和

注意:将所有耦合代码放在组合根中并不一定意味着必须将它们放在同一个方法或类中。您可以跨多个类组织它和/或使用中的约定使其可维护。但在一天结束时,应用程序应该负责其依赖关系,因此您不应该将此代码移动到其他应用程序层-将其保留在应用程序的启动层


项目B不需要知道关于IoC容器的任何信息。如果您很快采取这种方法,所有DLL都依赖于特定的IoC库

在Autofac中,您可以执行以下操作:

        builder.RegisterAssemblyTypes(typeof(ClassB).Assembly)
            .Where(x => typeof (ISomeInterface).IsAssignableFrom(x))
            .AsImplementedInterfaces();

在这里,我将从另一个DLL注册实现特定接口的所有内容。我对该程序集中的任何类都没有直接依赖关系,它们被声明为
internal
,以实现这一点。对于单元测试,我的测试项目使用[InternalsVisibleTo]直接实例化类,但不公开它们。

您使用的是什么IoC容器?但是如果您将unity容器从ProjectA传递到ProjectB,则会自动了解子类3和子类4…Hi@JuanR,AutoFac,但我确实把它抽象到了我自己的图书馆,因为我不想依赖vendorHi@Lepijohnny,是的,我可以将容器从ProjectA传递到ProjectB。但是既然ProjectB没有入口点,我应该创建一个特殊的方法来传递容器并注册子类3和4吗?谢谢@NightOwl888。。。但ProjectA需要了解ProjectB的实现,这对我来说还是有点脏。我不想让ProjectA知道ProjectB的潜在机制。我认为这可以通过将容器作为参数传递给ProjectB并在其中重新定义子类3和4来实现。此外,对于不存在ProjectA的ProjectB单元测试,您将如何在单元测试本身中注册这些类?ProjectB是什么类型的库?它是应用层、插件、组件库还是框架?如果是后两种情况中的一种,请参见上面的链接帖子。可以创建一个fluent builder,允许替换组件,同时还可以在一次调用中将其连接在一起。它只是一个包含webserviceHi使用的业务逻辑的类库,ISomeInterface如何知道使用什么实现?我看到它选择了唯一实现的接口?@doorman
AsImplementedInterfaces
将这些类注册为其所有实现的接口。e、 IBackgroundService也可能从ISomeInterface和IEmailService继承。现在我的应用程序可以请求一个IEmailService并获得一个,但我不需要注册所有单独的接口。如果愿意,您可以单独注册。如果程序集B需要使用
ContainerBuilder
执行更复杂的注册工作,您可以使用Autofac
模块
将所有注册至少封装在一个位置,并将初始化代码简化回主程序集中。