接口实现理念

时间:2015-01-21 21:08:32

标签: c# interface

在C#中,不允许实现这样的界面:

public interface ITest
{
    IEnumerable<int> Numbers { get; set; }
}

public class CTest : ITest
{
    public List<int> Numbers { get; set; }
}

我的问题是:是否有一些软件理念使这种类型的实现错误?它是一种有争议的范式,有点像多重继承,其中争论已经发生了数十年?

我无法理解为什么这样的界面实现不能正常工作的原因。如果您了解ITest,那么您只能看到IEnumerable<int>的{​​{1}}部分。如果您了解CTest.Numbers,那么您可以使用整个CTest实施。由于List<int>来自List<int>,为什么它不能满足接口要求?

2 个答案:

答案 0 :(得分:9)

调用覆盖基本方法时子类返回子类型的能力return type covariance

在这种情况下,由于Numbers属性的设置器

,您的示例是不安全的
ITest t = new CTest();
t.Numbers = new HashSet<int>();

如果在ITest中只定义了一个getter,那么它是安全的,虽然C#仍然不允许它 - 但Java会这样做:

public interface Test {
    Iterable<Integer> getNumbers();
}

public class CTest implements Test {
    public List<Integer> getNumbers() {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        return numbers;
    }
}

答案 1 :(得分:3)

接口是合同。它告诉客户完全哪些方法/属性可用,完全输入和输出的类型。

当您告诉客户端任何实现ITest的类将接受任何IEnumerable<int>作为Numbers的值时,CTest类只会接受List<int> 1}},你违反了合同。

如果你想实现界面但是也暴露了一种更具体的集合类型,你可以显式地实现界面,但是你必须决定做什么是客户试图&#34;设定&#34;一个 IEnumerable<int>一个选项的List<int>只是在幕后制作List<int>

public class CTest : ITest
{
    public List<int> Numbers { get; set; }

    // satisfies the interface
    IEnumerable<int> ITest.Numbers { 
        get { return Numbers; } 
        set { Numbers = new List<int>(value); } 
    }

}

现在知道CTest的客户端可以使用List<int>属性,但只知道接口的客户端仍然可以设置集合而不进行转换。