在接口内部声明 IEnumerable<T> 而在具体 class 中声明 IList<T>

Having IEnumerable<T> declared inside interface while having IList<T> declared in concrete class

考虑一个例子:

我有一个这样的界面。我需要这个接口是协变的——这意味着我必须将我的泛型声明为“out”并使用 IEnumerable 而不是列表——仅此而已。我将使用它来简单地获取我需要的元素 - 无需插入任何内容。

    public interface IFoo<out T>
    {
          IEnumerable<T> Items { get; } 
    }

然后我的具体 class 声明如下:

    public class Foo : IFoo<Item>
    {
         // I have an error here : Type IList doesn't match the expected type IEnmerable
          IList<Item> Items { get; set; } 
    }

而且我想知道为什么这不可能?我的意思是 IList 继承自 IEnumerable 并且这种类型的代码完全可以正常工作。

public IEnumerable<Item> GetItems()
{
    return new List() { new Item())};
}

为什么可以做到?解决方法是什么?

我唯一的解决办法是我可以创建额外的 属性 或像这样的方法

public IEnumerable<Item> GetEnumerableItems()
{
   return Items;
}

但这对我来说似乎太老套了。我认为可能有更清洁的解决方案。

运行时不支持此功能。如果您要实现的接口具有 return 特定类型的 属性,则必须在您的实现中完全匹配该 return 类型。

Return Type Covariance 已添加到 C# 9 中,但不适用于此处(请参阅@JeroenMostert 的评论)。

您可以使用显式接口实现解决此问题:

public class Foo : IFoo<Item>
{
    IList<Item> Items { get; set; }
    IEnumerable<Item> IFoo<Item>.Items => Items;
}

SharpLab.

拥有 Foo 的消费者可以访问 Foo.Items 并获得 IList<Item>。只有 IFoo<Item> 的消费者可以访问 IFoo<Item>.Items,并将取回 IEnumerable<Item>.