2013-03-19 176 views
10

时,为什么我不能使用兼容的具体类型,我希望能够做这样的事情:实现接口

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和类使用列表,但列表一个IEnumerable .....

我能做些什么?我不想在类中指定IEnumerable,我想使用实现IEnumerable的具体类型,如列表...

+2

“我想使用实现IEnumerable的具体类型,像List ...“ - 为什么? – jcollum 2013-03-19 02:43:45

回答

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>)会发生什么情况。

+0

在处理将JSON对象反序列化为必须具有接口参数的具体对象时,这变得非常有用。通过提供具体参数,解串器可以找出一种方法来实例化参数的对象。 – 2013-08-09 15:48:55

4

虽然List实现IEnumerable,但这不是接口的工作方式。该接口准确指定哪些类型需要公开属性。如果你创建了一个通用的接口一样

public interface IFoo<T> where T : IEnumerable<int> 
{ 
    T integers { get; set; } 
} 

然后,您可以使用IFoo<List<int>>实现它在你希望的方式。

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; 
    } 
} 
+0

我认为这有效(我现在无法测试),但我不明白为什么。为什么从接口移除setter允许'List '实现'IEnumerable '?编译器是否在每个方向进行类型检查(即你可以实现一个'List Integers {set; }'用IEnumerable 整数{private get;设置}? – Bobson 2013-03-19 03:53:22

+0

我假设示例代码中的'Bar'实现了'IFoo'?如果是这样,代码不能解决问题。相同的编译错误:'Test.Bar.Integers'无法实现Test.IFoo.Integers',因为它没有匹配的返回类型'System.Collections.Generic.IEnumerable ''。我错过了什么吗? – Peter 2015-04-23 18:06:37