我希望能够做到这样的事情:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test
{
public interface IFoo
{
IEnumerable<int> integers { get; set; }
}
public class Bar : IFoo
{
public List<int> integers { get; set; }
}
}
为什么编译器会抱怨..?
Error 2 'Test.Bar' does not implement interface member 'Test.IFoo.integers'. 'Test.Bar.integers' cannot implement 'Test.IFoo.integers' because it does not have the matching return type of 'System.Collections.Generic.IEnumerable<int>'.
我理解接口说IEnumerable而且类使用List,但List 是 IEnumerable .....
我该怎么办?我不想在类中指定IEnumerable,我想使用一个实现IEnumerable的具体类型,比如List ...
答案 0 :(得分:12)
这是类型协方差/反补贴问题(请参阅http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#C.23)。
有一种解决方法:使用显式接口,如下所示:
public class Bar : IFoo {
private IList<int> _integers;
IEnumerable<int> IFoo.integers {
get { return _integers };
set { _integers = value as IList<int>; }
}
public IList<int> integers {
get { return _integers; }
set { _integers = vale; }
}
}
请注意,integers
应该是TitleCased,以符合.NET的指导原则。
希望您可以在上面的代码中看到问题:IList<int>
仅与访问者IEnumerable<int>
兼容,但与设置无关。如果有人拨打IFoo.integers = new Qux<int>()
(Qux : IEnumerable<int>
但不 Qux : IList<int>
),会发生什么情况。
答案 1 :(得分:4)
虽然List实现了IEnumerable,但这不是接口的工作方式。接口确切地指定了需要为属性公开哪些类型。如果您创建了一个通用界面,如
public interface IFoo<T> where T : IEnumerable<int>
{
T integers { get; set; }
}
然后,您可以使用IFoo<List<int>>
以您期望的方式实现它。
答案 2 :(得分:3)
除非你在幕后进行,否则你无法使用具体类型。问题是你可以获取和设置属性。
您的界面指定该属性的类型为IEnumerable<int>
。 HashSet<int>
实施IEnumerable<int>
。这意味着以下应该可以正常工作:
IFoo instance = new Bar();
instance.integers = new HashSet<int>();
但是,由于您尝试使用具体类型List<int>
来实现接口,因此分配无法工作。
最简单的修复,假设您不需要经常重新分配集合,将只为集合指定一个getter:
public interface IFoo
{
IEnumerable<int> Integers { get; }
}
public class Bar
{
public List<int> Integers { get; private set; }
public Bar(List<int> list)
{
Integers = list;
}
}