我们最近偶然发现了数据收集计划中的一个问题。我们使用通用接口来创建一个通用工作流程,通过配置中的具体实现,可以轻松地为不同的数据输入进行定制。最近针对缺失数据错误的修复程序通常如下所示:
[TestFixture]
internal class GenericsTest
{
[Test]
public void Config()
{
new Collector(new Search());
}
internal class Collector
{
public Collector(Clues<Where, What> foo)
{
}
}
internal interface Clues<T, P>
{
}
internal class Search : Clues<Where, Item>
{
}
internal class Where
{
}
internal class Item : What
{
}
internal interface What
{
}
}
Config正在使用特定搜索初始化特定收集器。收集器本身只期望具有具体类的通用接口Where和interface作为参数。 Search类应该通过实现具有Where类的通用Clues接口和本身实现What接口的Item类来满足这些期望。 相反,搜索的初始化失败,因为它无法在特定实现和一般期望之间建立连接。
Error CS1503 Argument 1: cannot convert from 'UnitTest.GenericsTest.GenericsTest.Search' to 'UnitTest.GenericsTest.GenericsTest.Clues<UnitTest.GenericsTest.GenericsTest.Where, UnitTest.GenericsTest.GenericsTest.What>'
我们尝试转换为所需的类型,但它只将错误转移到运行时。
一般概念是,工作流保持尽可能通用,配置负责所有特定要求。所需的具体方法应该在item类中引入并隐藏在接口后面,以避免不必要的混乱。
有没有一种特定的方法在C#中编写这样的实现?
答案 0 :(得分:3)
您必须更改Clues
的定义
并使用covariance
协方差: 使您可以使用比最初指定的更多派生类型
internal interface Clues<T, out P>
修改强>
如果您无法更改界面,那么您可以更改Collector
类以使用带有约束的泛型:
internal class Collector<TWhere,TWhat> where TWhere:Where where TWhat:What
{
public Collector(Clues<TWhere, TWhat> foo)
{
}
}
然后,您必须准确指定您要使用的类型:
public void Config()
{
new Collector<Where,Item>(new Search());
}