gpt4 book ai didi

c# - 使用 DI 创建具有上下文的插件实例

转载 作者:太空宇宙 更新时间:2023-11-03 11:07:13 25 4
gpt4 key购买 nike

我正在重构我们的应用程序以包括依赖注入(inject)(通过构造函数注入(inject))并且遇到了一个棘手的极端情况:

我们目前有 ImageViewer 对象,它们在实例化时会在程序集中搜索 ImageViewerPlugin(一个抽象基类)实例,并使用反射来实例化它们。这是在 ImageViewer 的构造函数中使用类似于以下的方法(在循环中为所有具体插件类型调用)完成的:

private ImageViewerPlugin LoadPlugin(Type concretePluginType)
{
var pluginConstructor = concretePluginType.GetConstructor(
BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public,
null,
new[] { typeof(ImageViewer) },
null);

return (ImageViewerPlugin) pluginConstructor.Invoke(
new object[] { constructorParameter });
}

ImageViewerPlugin 类大致如下所示:

internal ImageViewerPlugin
{
protected ImageViewer _viewer;
protected ImageViewerPlugin(ImageViewer viewer)
{
_viewer = viewer;
}
}

具体的实现大概是这样的:

internal AnImageViewerPlugin
{
public AnImageViewerPlugin(ImageViewer viewer) : base(viewer)
{
}
}

每个 ImageViewer 实例都有自己的 ImageViewerPlugin 实例集合。

既然应用程序被重构为使用 DI 容器和构造函数注入(inject),我发现这些插件具有需要由 DI 容器解析的依赖项(以前通过使用全局静态类隐藏),但是我不确定如何在不使用服务定位器(一种反模式)的情况下做到这一点。

最明智的解决方案似乎是使用 DI 创建这些插件实例。这将允许我添加额外的构造函数参数,以通过构造函数注入(inject)来注入(inject)它们所依赖的依赖项。但是,如果我这样做,我如何在注入(inject)其余参数值的同时传递特定的 viewer 参数值?

我认为 ImageViewerPluginFactory 有助于实现这一点,但看不到如何实现这样的工厂,因为每个插件可能具有不同的构造函数签名。

我该如何解决这种情况?还是我的处理方式完全错误?

最佳答案

因此,您有一个 ImageViewer 依赖于 ImageViewerPlugin 实例的集合,每个实例都依赖于 n 个 ImageViewer,后者又依赖于ImageViewerPlugin 实例,每个都依赖于 n 个 ImageViewer,而 ImageViewer 又依赖于 ImageViewerPlugin 实例的集合,每个实例都依赖于一个......图片:-)

这是一个循环引用。撇开整个 DI 容器不谈,手动执行此操作时您将如何创建此层次结构?使用构造函数注入(inject)你不能。从下面的例子可以看出:

var plugin = new ImageViewerPlugin( [what goes here?] );
var viewer = new ImageViewer(plugin);

你将不得不以某种方式打破这个依赖循环,一般的建议是在这种情况下退回到属性注入(inject):

var plugin = new ImageViewerPlugin();
var viewer = new ImageViewer(plugin);

// Property injection
plugin.Viewer = viewer;

但更重要的是,您应该仔细查看应用程序的设计,因为循环引用通常表明设计存在问题。例如,仔细查看插件需要查看器的哪些行为以及查看器需要插件的哪些行为。您可以将其提取到另一个类中,如下所示:

var imageServices = new ImageServices();
var plugin = new ImageViewerPlugin(imageServices);
var viewer = new ImageViewer(imageServices, plugin);

这样就完全解决了问题,但是否可行,还要看你的情况。

使用最后一个解决方案,使用 Simple Injector 注册会非常简单。当使用属性注入(inject)打破依赖时,你可以使用 RegisterInitializer(Action)方法。它允许您打破依赖循环。例如:

container.RegisterInitializer<ImageViewer>(viewer =>
{
foreach (var plugin in viewer.Plugins)
{
plugin.Viewer = viewer;
}
});

关于c# - 使用 DI 创建具有上下文的插件实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15422461/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com