【问题标题】:Non-generic implementations of generic interfaces泛型接口的非泛型实现
【发布时间】:2014-11-18 15:29:12
【问题描述】:

我有以下 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&lt;Row&gt;'. There is no implicit reference conversion from 'GenericsIssueExample.ExampleRow' to 'GenericsIssueExample.IRow&lt;GenericsIssueExample.IEntry&gt;'.

这个错误在第27行,也就是ExampleGroup的定义:

class ExampleGroup : IGroup<ExampleRow>

我不明白为什么会发生这种情况,因为 ExampleRow 确实实现了 IRow&lt;IEntry&gt;。 (IRow&lt;ExampleEntry&gt;)。

如何更正上述代码以解决该错误?

【问题讨论】:

  • 您已将所有泛型参数声明为不变量(没有 inout 修饰符),因此该问题似乎是有效的。如果您的界面中只需要 gets,则添加适当的修饰符后可能会起作用。
  • 搜索词“协方差”...即stackoverflow.com/questions/16317541/… - 可能的最短摘要 - class A:B 并不意味着 IX&lt;A&gt;:IX&lt;B&gt;
  • @GáborBakos 我确实需要同时拥有gets 和sets,但我想我找到了另一个解决方案。将IGroup 更改为interface IGroup&lt;Row, Entry&gt; where Row : IRow&lt;Entry&gt; where Entry : IEntryExampleGroup 更改为class ExampleGroup : IGroup&lt;ExampleRow, ExampleEntry&gt; 是最好的解决方案吗?

标签: c# generics


【解决方案1】:

仅仅因为ExampleEntry 可以隐式转换为IEntry 并不意味着IRow&lt;ExampleEntry&gt; 可以转换为IRow&lt;IEntry&gt;。如果IRow 与其泛型参数是协变的,那么是的,那是可能的,但它不是现在这样,所以隐式转换是不可能的。

如果您可以将IRow&lt;ExampleEntry&gt; 隐式转换为IRow&lt;IEntry&gt;,则可以将Entries 属性设置为IEntry 类型的数组,该数组不是ExampleRow

【讨论】:

    【解决方案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; }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-19
      • 2020-03-02
      相关资源
      最近更新 更多