如何编写库而不强迫用户使用库的 IOC 容器

2024-03-19

简短的问题是: 给定一个图书馆warrants当应用程序使用该库时,在给定应用程序的情况下,将特定的 IOC 容器用于其内部warrants使用 IOC 容器来连接其依赖项,如果两个容器不同,它们如何才能很好地协同工作?

场景是,应用程序定义了依赖于库中的类型的类。因此,当应用程序容器尝试构建这样的类时,它需要知道如何解析库中的类型。

这是一个冗长的问题:

这个问题似乎之前已经以不同的形式被问过,但我似乎找不到我需要的答案,所以我将用一个假设的_over_simplified_具体例子来尝试一下。 我们希望编写一个用于日志记录的库,用户可以将其作为包包含在他们的解决方案中,以获得开箱即用的日志记录功能。 该库公开的公共接口是..

public interface ILogger {}

public interface ITarget {}

具体实现是

internal class Logger: ILogger { public Logger(ITarget target) {}}

internal class FileTarget : ITarget {}

要求是用户是否包含我们的包并定义一个具有 type 属性的类ILogger或者有一个类型为 ctor 的参数ILogger然后我们的库负责将该接口的具体实现注入到用户定义的类中。默认情况下,注入的记录器将转到文件系统进行日志记录,因为默认实现ITarget注入到ILogger实施是一个FileTarget由我们的图书馆提供。

如果用户决定编写一个类来实现ITarget接口然后我们的库将使用它来注入Logger类并且不使用其默认值FileTarget执行。

所以我想证明的是,它们是双向依赖关系。

  1. 我们的库依赖于用户的程序集,因为它需要扫描用户的程序集以加载任何扩展点(即ITarget实现)并在任何默认实现之前将它们注入到它自己的对象中。

  2. 用户的程序集取决于库,因为如果用户选择使用ILogger接口作为依赖项,那么该用户对象应该获得对我们的库在运行时提供的该接口的具体引用。

简单的解决方案是,如果用户和我们的库都使用相同的 IOC 容器,那么问题就解决了。但这是一个强有力的假设。我想做的是

  1. 将 IOC 容器与最能满足库要求的库一起使用,在我的例子中是 Ninject。
  2. 在运行时,以某种方式提供一种机制,让用户通过某些 API 调用我的库,这将确保 Ninject 被启动并扫描用户的程序集,并考虑所有扩展点来连接所有内容。

到目前为止一切顺利,完全可以实现,但棘手的部分来了。

  • 如果用户也在使用 Ninject,那么问题会自动解决,因为 Ninject 已经知道如何解析我们库中的接口。但是,如果用户决定使用他/她选择的 IOC 容器怎么办?

我几乎想用这样的接口在库中定义某种子容器功能

public interface IDependencyResolvingModule { T Get<T>(); []T GetAll<T>(); }

并提供一个使用我们库选择的容器(即 Ninect)的实现来解析上面定义的两个方法中请求的类型。

我希望用户的 IOC 容器具有一些功能,如果它无法解析依赖项(即ILogger),它应该挂入IDependencyResolvingModule实现并请求依赖。

这样我们的库就可以使用它选择的 IOC 容器,并且用户的代码可以解决其 IOC 容器不知道的依赖关系。如果 IOC 容器提供了一些功能来注册任何对象的单例实例,那么这个解决方案不会起作用吗?IDependencyResolverModules在执行程序集目录中的程序集中找到,当它们无法解析类型时,询问任何单例模块吗?

但除非有一个解决方案需要所有其他 IOC 容器都能容纳,否则还能如何解决这个问题呢?因此,几行中的问题是,当第三方程序集选择将 IOC 容器用于其内部时,有什么简单的解决方案,使得该库可以简单地为位于外部的 IOC 容器提供一种机制来挂钩并解决依赖关系住在图书馆里的。


我在这里看到几种可能的方法:

  1. 为所有流行的 IoC 容器编写默认注册器。它们中的每一个都应该放置在单独的组件中。然后开发人员可以选择他需要的容器并用它配置他的容器。

  2. 定义您自己的工厂抽象并编写将返回默认记录器的默认实现。让开发人员替代该工厂的实现。例如,为他最喜欢的容器配备适配器。这种方法与容器无关,因为开发人员可以只使用默认的工厂实现。但这种方式与自动接线无关。

  3. 第一种方法的懒惰变体。编写有关配置容器以使用默认实现的小手册。然后开发人员可以自己配置容器。

  4. 结合之前的所有解决方案来满足每个开发人员的需求。 :)

编辑:添加两个容器集成的示例

var allPublicInterfacesFromLibrary = typeof(AnyLibraryType)
    .Assembly.GetTypes()
    .Where(t => t.IsInterface && t.IsPublic);

foreach (var libraryInterface in allPublicInterfacesFromLibrary)
{
    var local = libraryInterface; //to prevent closure
    applicationContainer.Register(
        Component.For(libraryInterface)
        //delegate resolving
        .UsingFactoryMethod(k => libraryContainer.Resolve(local)) 
        //delegate lifetime management
        .LifestyleTransient() 
    );
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何编写库而不强迫用户使用库的 IOC 容器 的相关文章

随机推荐