我有以下代码段
using System.Collections.Generic;
public interface IInventoryItem {}
public class InventoryItem : IInventoryItem {}
public interface IInventory
{
IEnumerable<IInventoryItem> Items { get; }
}
public class Inventory : IInventory
{
public IEnumerable<InventoryItem> Items => items;
// IEnumerable<IInventoryItem> IInventory.Items => items;
private InventoryItem[] items = new InventoryItem[0];
}
我收到以下错误消息:
错误CS0738:
Inventory
未实现接口成员IInventory.Items.get
,并且最佳实现候选Inventory.Items.get
返回类型System.Collections.Generic.IEnumerable<InventoryItem>
与接口成员返回类型System.Collections.Generic.IEnumerable<IInventoryItem>
不匹配
添加IInventory.Items.get
的显式实现完全正确,但为什么有必要?
问题是:如果IEnumerable<InventoryItem>
是IEnumerable<IInventoryItem>
,为什么InventoryItem[]
不是Items.get
?
修改
关于为什么这很有趣: 我的假设:
IEnumerable<T>
将始终返回有效IEnumerable<IInventoryItem>
ParserFunctions
答案 0 :(得分:4)
这是必要的,因为IInventoryItem
不(并且不能)仅限于InventoryItem
实施。
如果您(或其他任何人)将编写另一个实现IInventoryItem
接口的类,那么实现IInventory
接口的任何类都将能够处理它,因为它只处理{{ 1}}接口,并不知道或关心具体的实现。
如果编译器允许在您的问题中编写IInventoryItem
类,那么它将无法处理任何其他实现Inventory
接口的类。
澄清:
IInventoryItem
属性返回Items
如果您添加了一个实现IEnumerable<InventoryItem>
的其他类,并且该类未从IInventoryItem
继承,则您的属性将无法返回InventoryItem
。
假设你添加这个类:
IEnumerable
您当前的public class MyNotRelatedInventoryItem : IInventoryItem
{ /* implementation here */ }
媒体资源永远无法容纳Items
IEnumerable
,因为它与您的MyNotRelatedInventoryItem
课程无关。
答案 1 :(得分:3)
除了佐哈已经提到过的内容之外,以下是如何用泛型实现你想要的东西:
public interface IInventoryItem {}
public class InventoryItem : IInventoryItem {}
public interface IInventory<T> where T : IInventoryItem
{
IEnumerable<T> Items { get; }
}
public class Inventory : IInventory<InventoryItem>
{
public IEnumerable<InventoryItem> Items => items;
private InventoryItem[] items = new InventoryItem[0];
}
然而,这有一个缺点,即整个接口IInventory
是通用的,因为属性不是通用的。为了避免这种情况,你可以创建一个GetItems
- 方法instea,可以是通用的。
当您有一个界面时,您必须使用该界面定义的完全相同的签名来实现它。出于同样的原因,您无法执行以下操作:
interface MyInterface
{
A A { get; }
}
class A : MyInterface
{
public B A { get; private set; } // this will NOT implement the interface, although B derives from A
}
class B : A { }
答案 2 :(得分:2)
您的属性返回类型与接口不匹配,因此编译器不会将其视为接口实现。所以你需要把它改成
public IEnumerable<IInventoryItem> Items => items;
而不是
public IEnumerable<InventoryItem> Items => items;
由于存在从InvetoryItem
到IInventoryItem
的隐式转换,编译器就可以了
这是可能的,因为您只返回该值,并且编译器知道您的数组中的每个InvetoryItem
都可以转换为IInventoryItem
类型,而不会抛出异常。
如果您的界面如下所示:
public interface IInventory
{
IEnumerable<IInventoryItem> Items { get; set; }
}
这是不可能的,以下代码
public IEnumerable<IInventoryItem> Items
{
get { return items; }
set { items = value; }
}
会引发以下编译错误:
错误CS0266
无法隐式转换类型&#39; System.Collections.Generic.IEnumerable&#39;到&#39; ConsoleApplication1.InventoryItem []&#39;。 存在显式转换(您是否错过了演员?)
这意味着编译器无法将任何IInventoryItem
隐式转换为InventoryItem
,因为它无法确保此转换始终成功。
你必须像这样明确地转换:
public IEnumerable<IInventoryItem> Items
{
get { return items; }
set { items = (InventoryItem[])value; }
}
但如果数组不完全由InvetoryItem
个对象构成,则会发生异常。