假设我具有强名称程序集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_v1
和IPlugin_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_v1
和Interfaces_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";
}