具体类的数组与接口数组不协变

Kri*_*ris 3 d

我在为我的dataaccess.mysqlclient模块提供抽象基础层时遇到一些问题,我已经为最低要求定义了一堆接口,并且实现了一堆类.

现在dmd编译器抱怨:

Error: function dataaccess.mysqlclient.MySqlReader.columns of type @property MySqlColumnInfo[]() overrides but is not covariant with dataaccess.dbclient.IDbReader.columns of type @property IDbColumnInfo[]() Exit code 1

相关的代码行如下所示:

IDbReader:

interface IDbReader
{
    @property IDbColumnInfo[] columns();
    // ... 
}
Run Code Online (Sandbox Code Playgroud)

MySqlReader:

class MySqlReader : IDbReader
{
    private MySqlColumnInfo[] _columns;
    @property public MySqlColumnInfo[] columns() {return _columns;}
    // ... 
}
Run Code Online (Sandbox Code Playgroud)

我可以通过几种方法解决这个编译器问题;

  • 声明具体属性 IDbColumnInfo[]
  • 将数组包装在列表类中

如果我再考虑一下,可能还需要更多.但这些似乎都不是很优雅.

这里有一个大问题:

  • 我忽略了简单的事情吗?
  • 实现数组是否可以与接口数组协变?

此外,我无法想象编译器投诉的原因.我的代码中有更复杂的结构,编译得很好.因此,如果有人可以解释为什么这不会起作用,那就非常感激了.

Vla*_*eev 6

您遇到了阵列协方差的问题.

我们假设你的代码编译得很好.现在,请考虑以下代码:

class SomeOtherColumnInfo : IDbColumnInfo {}

IDbReader reader = new MySqlReader(...);
IDbColumnInfo[] columns = reader.columns;
columns[3] = new SomeOtherColumnInfo(); // OK
Run Code Online (Sandbox Code Playgroud)

由于数组是可变的,我们可以使用其他IDbColumnInfo派生类的实例覆盖其元素.问题在于我们还在修改私有_columns字段MySqlReader.所以,现在我们有一个SomeOtherColumnInfo实例作为MySqlColumnInfo[]数组的成员.因此,我们在不使用强制转换或其他不安全代码的情况下破坏了类型系统.由于预期编译器会阻止我们意外地执行此操作,因此它将拒绝隐式地将可变类的数组转换为其他类的数组,即使这些类是相关的.

现在,我认为如果返回的数组不可变(即const或不可变),D允许编译是有意义的.但是,编译器也不喜欢这样.我不知道这是否属于遗漏,或者我有什么理由不知道.