问题
我有两个接口(interface) IImporter
和 IExporter
以及一个处理这些接口(interface)实例的类:
class IoManager
{
public ReadOnlyCollection<IImporter> Importers { get; }
public ReadOnlyCollection<IExporter> Exporters { get; }
// ...
}
在这个类中,我想实现一个方法Add(...)
,它可以添加一个导入器或一个导出器。
我知道我可以为两个接口(interface)创建一个重载
public void Add(IExporter exporter);
public void Add(IImporter importer);
问题是,如果我想通过 Add(...)
函数添加一个实现两个接口(interface)的对象,例如 CsvIo : IImporter, IExporter
,我会得到一个模棱两可的调用编译器错误,因为 CsvIo
被两个重载接受。
我不想做的事
- 我不想将重载重命名为不同的名称,因为大多数类型都实现了这两个接口(interface),而且我希望实现
IExporter
、IImporter
或两者。 - 我不想创建一个由两个接口(interface)实现的“父”接口(interface),因为这看起来像一个hacky解决方案
- 我不想在
Add(...)
调用中转换类型,例如Add((IImporter) CsvIoInstance)
,因为这表明只有使用这种类型的进口商。但是两个重载都会检查对象是否实现了两个接口(interface)并将其相应地添加到两个列表中。
问题
有没有办法以连贯的方式接受不同的类型(以便每种类型的调用看起来都一样)?
编辑
澄清我的实现:这是插件系统的一部分。我想添加多种方式来存储我的数据(以便它可以被其他应用程序使用)。 IExporter
接口(interface)用于存储数据,而IImporter
接口(interface)用于加载数据。 IoManager
管理所有已注册的插件。当然,一个类可能(并且可能很常见)同时实现某种文件格式的导出和导入。这就是为什么我希望 Add(...)
函数在所有情况下都相似。
但是,再次考虑(如评论中所述)插件仅在运行时已知,我认为这使得歧义成为一个过时的问题。所以这只与内置类型有关。
最佳答案
我想特别关注一句话:
I don't want to cast types in the
Add(...)
call, likeAdd((IImporter) CsvIoInstance)
, because that suggests that only the importer of this type is used. But both overloads check if the object implements both interfaces and adds it to both lists accordingly.
您当前的设计已经放弃了类型安全的目标之一:避免运行时类型检查。理想情况下,采用IImporter
参数的方法应该仅将该参数用作IImporter
。这在方法的调用者和实现者之间形成了一种“契约”:实现者相信调用者会提供它需要的东西,而调用者相信实现者只会以这种方式使用它。 (另请参阅:Principle of least astonishment。)
假设您是此类的消费者。有一个 IImporter
集合和一个带有签名 Add(IImporter foo)
的方法。您希望该方法做什么? 我希望它将 foo
添加到 IImporters
列表中 - 我不希望它也做一些事情否则因为我的对象恰好实现了另一个接口(interface)(例如 IExporter
)。以这种方式使用类型系统会“背叛”您与调用者建立的契约。
将您的方法名称更改为 AddImporter
和 AddExporter
,然后让每个方法仅将参数添加到相应的列表中。这解决了重载解析的问题,意味着调用者得到的正是他们所要求的。
关于c# - 接受两个接口(interface)之一的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47857257/