我有下面的片段
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[]
不是InventoryItem[]
?
编辑:
关于为什么这很有趣:我的假设:
Items.get
将始终返回一个有效的IEnumerable<IInventoryItem>
发布于 2018-01-25 03:44:23
这是必要的,因为IInventoryItem
是,而不是(也不能)仅限于由InventoryItem
实现。
如果您(或其他任何人)将编写另一个实现IInventoryItem
接口的类,那么实现IInventory
接口的任何类都将能够处理这个问题,因为它只处理IInventoryItem
接口,不知道或不关心具体的实现。
如果编译器允许像在您的问题中那样编写Inventory
类,那么它将无法处理实现IInventoryItem
接口的任何其他类。
为求澄清:
Items
属性返回一个IEnumerable<InventoryItem>
。
如果添加了实现IInventoryItem
的不同类,且该类没有从InventoryItem
继承,则属性将无法返回该类的IEnumerable
。
假设您添加了这个类:
public class MyNotRelatedInventoryItem : IInventoryItem
{ /* implementation here */ }
您当前的Items
属性将永远无法保存IEnumerable
of MyNotRelatedInventoryItem
,因为它与InventoryItem
类没有任何关联。
发布于 2018-01-25 03:56:10
我补充了Zohar已经提到的内容,下面是如何通过泛型实现您想要的:
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
-method 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 { }
发布于 2018-01-25 03:59:21
属性返回类型与接口类型不匹配,因此编译器不将其视为接口实现。所以你需要把它改为
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不能隐式地将“System.Collections.Generic.IEnumerable”类型转换为“ConsoleApplication1.InventoryItem[]”。显式转换存在(您缺少强制转换吗?)
这意味着编译器不能隐式地将任何IInventoryItem
转换为InventoryItem
,因为它无法确保该转换始终成功。
您必须像这样显式地转换:
public IEnumerable<IInventoryItem> Items
{
get { return items; }
set { items = (InventoryItem[])value; }
}
但是,如果数组不是完全由InvetoryItem
对象组成,则可能出现异常。
https://stackoverflow.com/questions/48441990
复制