假设我具有强名称程序集Interfaces.dll的版本1,其中包含IPlugin接口:

public interface IPlugin
{
    void InstallSelf(IPluginManager pluginManager);
}


已经实现了许多插件,一切运行顺利。

有一天,已经确定插件可能应该具有名称,以便我们可以查看已加载的插件。因此,我们生成的Interfaces.dll版本2包含:

public interface IPlugin
{
    string PluginName { get; }
    void InstallSelf(IPluginManager pluginManager);
}


因为我不能期望所有的插件实现者都立即更新他们的插件,所以我想创建一个适配器,该适配器向旧的插件版本添加“ Unknown”的PluginName。有没有办法实现这样的适配器?我希望它看起来像这样:

public sealed class PluginAdapter_v1_v2 : IPlugin[v2]
{
    private readonly IPlugin[v1] _plugin;

    public PluginAdapter_v1_v2(IPlugin[v1] plugin)
    {
        _plugin = plugin;
    }

    public string PluginName => "Unknown";

    public void InstallSelf(IPluginManager pluginManager)
    {
        _plugin.InstallSelf(pluginManager);
    }
}


但是因为它们都被称为IPlugin,所以这行不通。一种替代方法是将IPlugin重命名为IPlugin_v1IPlugin_v2,或者对其名称空间进行类似的重命名,但是这需要在每次有新版本的Interfaces.dll时重命名接口(或名称空间)。 ,并且要求实现者在更新为最新程序集版本时更改对接口(或名称空间)的所有引用。所以,问题又来了:

是否可以实现这种适配器而无需重命名IPlugin或其名称空间?

最佳答案

有一种方法可以做到这一点,但是它已经花了很长时间了。在此过程结束时,我们将最终得到一个从IPlugin [v1]到IPlugin [v2]的适配器类。

引用两个版本的Interfaces.dll


创建一个要在其中放置适配器类的项目。
照常在Visual Studio中添加对最新版本的引用。
右键单击项目,然后选择“卸载项目”
再次右键单击该项目,然后选择“编辑[项目名称] .csproj”
查找如下所示的部分:

<Reference Include="Interfaces">
  <HintPath>path\to\library\v2\Interfaces.dll</HintPath>
</Reference>


并替换为:

<Reference Include="Interfaces_v1">
  <HintPath>path\to\library\v1\Interfaces.dll</HintPath>
  <Aliases>Interfaces_v1</Aliases>
</Reference>
<Reference Include="Interfaces_v2">
  <HintPath>path\to\library\v2\Interfaces.dll</HintPath>
  <Aliases>Interfaces_v2</Aliases>
</Reference>

保存并关闭项目文件
右键单击项目,然后选择“重新加载项目”


引用两个版本的IPlugin

Aliases元素添加到项目文件意味着不再将类型导入到全局命名空间中,而是将其导入到Interfaces_v1Interfaces_v2命名空间中。这意味着我们可以使用不同的名称访问两个IPlugin版本:


在适配器源文件的顶部(在任何using语句之前),添加以下内容:

extern alias Interfaces_v1;
extern alias Interfaces_v2;

(可选)要稍微整理一下代码,也可以添加一些类型别名:

using IPlugin_v1 = Interfaces_v1::Interfaces.IPlugin;
using IPlugin_v2 = Interfaces_v2::Interfaces.IPlugin;



实施适配器

    public sealed class PluginAdapter_v1_v2 : IPlugin_v2
    {
        private readonly IPlugin_v1 _pluginV1;

        public PluginAdapter_v1_v2(IPlugin_v1 pluginV1)
        {
            _pluginV1 = pluginV1;
        }

        public string Name => _pluginV1.Name;

        public string Version => "Unknown";
    }

10-07 14:32