在接口内部声明 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;
}
拥有 Foo
的消费者可以访问 Foo.Items
并获得 IList<Item>
。只有 IFoo<Item>
的消费者可以访问 IFoo<Item>.Items
,并将取回 IEnumerable<Item>
.
考虑一个例子:
我有一个这样的界面。我需要这个接口是协变的——这意味着我必须将我的泛型声明为“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;
}
拥有 Foo
的消费者可以访问 Foo.Items
并获得 IList<Item>
。只有 IFoo<Item>
的消费者可以访问 IFoo<Item>.Items
,并将取回 IEnumerable<Item>
.