3

我在为我的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();
    // ... 
}

MySqlReader:

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

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

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

如果我再想一想,可能还有更多。不过,这些看起来都不是很优雅。

大问题来了:

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

我也无法想象编译器抱怨的原因。我的代码中有更复杂的结构,它们已经编译得很好。因此,如果有人可以解释为什么这不能按原样工作,那将不胜感激。

4

1 回答 1

6

您遇到了数组协方差的问题。

假设您的代码编译良好。现在,考虑以下代码:

class SomeOtherColumnInfo : IDbColumnInfo {}

IDbReader reader = new MySqlReader(...);
IDbColumnInfo[] columns = reader.columns;
columns[3] = new SomeOtherColumnInfo(); // OK

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

现在,我认为如果返回的数组不是可变的(即 const 或不可变的),D 允许编译是有意义的。但是,编译器也不喜欢这样。我不知道这是否是一个遗漏,或者是否有我不知道的原因。

于 2013-08-10T04:03:48.877 回答