泛型接口的非泛型实现

本文关键字:实现 泛型 泛型接口 | 更新日期: 2023-09-27 18:30:44

我有以下一组 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>)。

我将如何更正上面的代码来解决该错误?

泛型接口的非泛型实现

仅仅因为ExampleEntry可以隐式转换为IEntry并不意味着IRow<ExampleEntry>可以转换为IRow<IEntry>。 如果IRow就其泛型参数而言是协变的,那么是的,这是可能的,但它不是现在的样子,所以隐式转换是不可能的。

如果可以将IRow<ExampleEntry>隐式转换为IRow<IEntry>则可以将Entries属性设置为不是ExampleRowIEntry类型的数组。

问题是你在不适用的地方混合了接口和泛型。在您的示例中很难看到,但是如果您修复命名约定,以便所有泛型类型参数都命名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; }
        }
    }
}