D 具体类数组与接口数组不协变
我在为我的D 具体类数组与接口数组不协变,d,D,我在为我的dataaccess.mysqlclient模块提供一个抽象的基础层时遇到了一个小问题,在这个模块中,我定义了一组接口来满足最低要求,并定义了一组实现这些要求的类 现在,dmd编译器抱怨: 错误:@property MySqlColumnInfo[]()类型的函数dataaccess.mysqlclient.MySqlReader.columns覆盖但不与@property IDbColumnInfo[]类型的dataaccess.dbclient.idbdreader.columns
dataaccess.mysqlclient
模块提供一个抽象的基础层时遇到了一个小问题,在这个模块中,我定义了一组接口来满足最低要求,并定义了一组实现这些要求的类
现在,dmd编译器抱怨:
错误:@property MySqlColumnInfo[]()类型的函数dataaccess.mysqlclient.MySqlReader.columns覆盖但不与@property IDbColumnInfo[]类型的dataaccess.dbclient.idbdreader.columns共变()
退出代码1
相关代码行如下所示:
IDB阅读器:
interface IDbReader
{
@property IDbColumnInfo[] columns();
// ...
}
MySqlReader:
class MySqlReader : IDbReader
{
private MySqlColumnInfo[] _columns;
@property public MySqlColumnInfo[] columns() {return _columns;}
// ...
}
有几种方法可以解决这个编译器问题
- 将具体属性声明为
IDbColumnInfo[]
- 将数组包装在列表类中
- 我是否忽略了一些简单的事情李>
- 实现的数组可以与接口的数组协变吗
此外,我真的无法想象编译器抱怨的原因。我的代码中有更复杂的结构,它们编译得很好。因此,如果有人能解释为什么这不能按原样工作,我们将不胜感激。您遇到了这样的问题 让我们假设您的代码编译得很好。现在,考虑下面的代码:
class SomeOtherColumnInfo : IDbColumnInfo {}
IDbReader reader = new MySqlReader(...);
IDbColumnInfo[] columns = reader.columns;
columns[3] = new SomeOtherColumnInfo(); // OK
由于数组是可变的,我们可以用其他IDbColumnInfo
派生类的实例覆盖它的元素。问题是我们还修改了MySqlReader
的私有\u列
字段。因此,现在我们有一个SomeOtherColumnInfo
实例作为MySqlColumnInfo[]
数组的成员。因此,我们在不使用强制转换或其他不安全代码的情况下破坏了类型系统。由于编译器会意外地阻止我们这样做,因此它将拒绝隐式地将可变类数组转换为其他类的数组,即使这些类是相关的
现在,我认为如果返回的数组不可变(即const或immutable),则D允许编译是有意义的。然而,编译器也不喜欢这样。我不知道这是否是遗漏,或者是否有我不知道的原因。我也这么想,但不明白为什么会造成问题。因为,据我所知,
SomeOtherColumnInfo
在本例中必须是MySqlColumnInfo
的子类。换言之;我不明白这是如何破坏类型系统的。@克里斯想一想,如果您将MySqlReader[]
转换为idbdreader[]
,然后在其上附加一个PosixReader
,或者将其中一个元素替换为PosixReader
,会发生什么。您只需将一个PosixReader
放入真正的MySqlReader[]
数组中,这肯定会破坏类型系统。一般来说,将DerivedClass
的容器转换为BaseClass
的容器是没有意义的,就像一开始看起来的那样。@JonathanMDavis:是的,我有点明白,但我不能真正理解他们都实现了相同的契约,所以应该放在相同的位置。如果它们都不是Duck
,程序员就不会那样标记它们了,对吗?只要类型系统在该场景中断言PosixReader
是MySqlReader
的子类。List
不是c#中List
的一个子类吗?(我相信是的,但还没有检查)问题似乎可以通过使用MySqlColumnInfoList:ArrayWrapper来解决!(IDbColumnInfo)
这里。现在,我还需要在一些情况下这样做。引用MSDN:“由于数组协方差,对引用类型数组元素的赋值包括运行时检查,以确保分配给数组元素的值实际上是允许的类型。”这是在C#中允许List成为List的子类的唯一原因。需要认识到的重要一点是,它们不实现相同的约定,因为数组有两个操作-get元素,它实现协方差(因为它们返回一个超类型),set元素(或append元素),它,因为它将新元素作为参数,所以需要逆变。因此,无论您以何种方式施放阵列,都必须放弃其一半契约。因此,可以对称地将对象[]之类的东西投射到Apple[*],其中T[*]是一个“盲数组”或“逆变数组”,它只支持赋值和追加,而不支持查找。