我有以下3个接口组和3个所述接口的实现。接口使用泛型定义,最顶层接口需要其参数来扩展第二个接口;与第三个接口相同。这些类没有通用参数,而是实现具有特定类的接口,每个类都满足接口的要求。
namespace GenericsIssueExample
{
interface IGroup<Row> where Row : IRow<IEntry>
{
Row[] Rows {
get;
set;
}
}
interface IRow<Entry> where Entry : IEntry
{
Entry[] Entries {
get;
set;
}
}
interface IEntry
{
int Value {
get;
set;
}
}
class ExampleGroup : IGroup<ExampleRow>
{
private ExampleRow[] rows;
public ExampleRow[] Rows {
get { return rows; }
set { rows = value; }
}
}
class ExampleRow : IRow<ExampleEntry>
{
private ExampleEntry[] entries;
public ExampleEntry[] Entries {
get { return entries; }
set { entries = value; }
}
}
class ExampleEntry : IEntry
{
private int val = 0;
public int Value {
get { return val; }
set { val = value; }
}
}
}
当我尝试编译上面的代码时,我得到以下编译错误:
The type 'GenericsIssueExample.ExampleRow' cannot be used as type parameter 'Row' in the generic type or method 'GenericsIssueExample.IGroup<Row>'. There is no implicit reference conversion from 'GenericsIssueExample.ExampleRow' to 'GenericsIssueExample.IRow<GenericsIssueExample.IEntry>'.
此错误在第27行,即ExampleGroup
:
class ExampleGroup : IGroup<ExampleRow>
我不明白为什么会这样,因为ExampleRow
确实实现了IRow<IEntry>
。 (IRow<ExampleEntry>
)。
如何更正上述代码以解决该错误?
答案 0 :(得分:4)
只是因为ExampleEntry
可以隐式转换为IEntry
并不意味着IRow<ExampleEntry>
可以转换为IRow<IEntry>
。如果IRow
对于其泛型参数是协变的,那么是的,这是可能的,但它不是现在的,所以隐式转换是不可能的。
如果您可以隐式地将IRow<ExampleEntry>
转换为IRow<IEntry>
,那么您可以将Entries
属性设置为IEntry
类型的数组,而不是{{1} }}
答案 1 :(得分:2)
问题是你在不适用的地方混合接口和泛型。在您的示例中很难看到,但是如果您修复了命名约定,所以所有泛型类型参数都被命名为TSomething
,那么它就会很清楚。
一旦我们这样做,那么很明显我们要指定我们想要一行实现IEntry
的类,而不是一行IEntry
个实例。
这是一个有效的例子:
namespace GenericsIssueExample
{
interface IGroup<TRow, TEntry>
where TRow : IRow<TEntry>
where TEntry : IEntry
{
TRow[] Rows
{
get;
set;
}
}
interface IRow<TEntry> where TEntry : IEntry
{
TEntry[] Entries
{
get;
set;
}
}
interface IEntry
{
int Value
{
get;
set;
}
}
class ExampleGroup : IGroup<ExampleRow, ExampleEntry>
{
private ExampleRow[] rows;
public ExampleRow[] Rows
{
get { return rows; }
set { rows = value; }
}
}
class ExampleRow : IRow<ExampleEntry>
{
private ExampleEntry[] entries;
public ExampleEntry[] Entries
{
get { return entries; }
set { entries = value; }
}
}
class ExampleEntry : IEntry
{
private int val = 0;
public int Value
{
get { return val; }
set { val = value; }
}
}
}