情景是这样的,应用程序定义了依赖于库中类型的类。因此,当应用程序容器尝试构建这样的类时,它需要知道如何解析存在于库中的类型。
以下是冗长的问题:
这个问题似乎以不同的形式在SO上被问过,但我似乎找不到我需要的答案,所以我将用一个假想的、过于简化的具体例子来尝试回答这个问题。 我们想编写一个日志记录库,用户可以将其作为包包含在他们的解决方案中,以获得开箱即用的日志记录功能。 该库公开的接口为... public interface ILogger {} public interface ITarget {}
具体实现为
internal class Logger: ILogger { public Logger(ITarget target) {}}
internal class FileTarget : ITarget {}
要求是,如果用户包括我们的包并定义了一个类型为ILogger的属性的类或者有一个类型为ILogger的ctor参数,那么我们的库负责将该接口的具体实现注入到用户定义的类中。默认情况下,注入的记录器将进入文件系统进行记录,因为ILogger实现中注入的ITarget的默认实现是我们库中的FileTarget。
如果用户决定编写一个实现ITarget接口的类,那么我们的库将使用它来注入到Logger类中,而不使用其默认的FileTarget实现。
因此,我希望展示的是这里存在双向依赖关系。
1.我们的库依赖于用户的程序集,因为它需要扫描用户的程序集以加载任何扩展点(即ITarget实现)并将其在默认实现之前注入到自己的对象中。 2.用户的程序集依赖于库,因为如果用户选择定义一个依赖ILogger接口的类,则该用户对象应在运行时由我们的库提供该接口的具体引用。
简单的解决方案是,如果用户和我们的库都使用相同的IOC容器,那么问题就解决了。但这是一个强烈的假设。我想要做的是...
- 使用与库最符合要求的IOC容器,对我来说是Ninject。
- 在运行时,以某种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容器可以连接并解决位于库中的依赖项。