c#接口实现——为什么它不能构建

本文关键字:不能 构建 为什么 实现 接口 | 更新日期: 2023-09-27 18:15:28

很抱歉,如果这个问题之前已经被问到过,但实际上是不可能的谷歌。我认为int数组实现了IEnumerable,因此Thing应该能够实现IThing。为什么没有呢?

public interface IThing
{
    IEnumerable<int> Collection { get; }
}
public class Thing : IThing
{
    public int[] Collection { get; set; }
}

注意

public class Thing : IThing
{
    public int[] Array { get; set; }
    public IEnumerable<int> Collection
    {
         get
         {
              return this.Array;
         }
    }
}

很好。

c#接口实现——为什么它不能构建

对于要实现的接口,方法签名和返回类型必须相同,因此int[]可转换为IEnumerable这一事实恐怕没有什么区别。

接口实现必须准确地实现接口。这可以防止返回实现该接口的类型作为成员。

如果您希望这样做,一个选项是显式地实现接口:

public interface IThing
{
    IEnumerable<int> Collection { get; }
}
public class Thing : IThing
{
    public int[] Collection { get; set; }
    IEnumerable<int> IThing.Collection { get { return this.Collection; } }
}

这允许类的公共API使用具体类型,但接口实现要正确实现。

例如,使用上面的代码,你可以这样写:

internal class Test
{
    private static void Main(string[] args)
    {
        IThing thing = new Thing { Collection = new[] { 3, 4, 5 } };
        foreach (var i in thing.Collection)
        {
            Console.WriteLine(i);
        }
        Console.ReadKey();
    }
}

在不同的实现中属性的返回类型是不同的——返回int[]和返回IEnumerable<int>是不一样的。

就实现接口而言-类型必须完全匹配

这应该可以正常工作:

public class Thing : IThing
{
    public IEnumerable<int> Collection { get; set; }
}

你的实现应该准确地实现接口。

因为

IEnumerable<int> Collection { get; }

的签名不同。
int[] Collection { get; set; }

当你实现一个接口时,签名应该是完全相同的

这就是协方差/逆变性可以派上用场的地方。该特性允许您在泛型上定义in/out标记,并允许您执行以下操作:

public interface IThing<out T> where T : IEnumerable<int> {
    T Collection { get; }
}
public class Thing : IThing<int[]> {
    public int[] Collection { get; set; }
}

那将允许你定义其他实现,然后仍然使用它们一起作为IThing<IEnumerable<int>> s。

public class Thing2 : IThing<List<int>> {
    public List<int> Collection { get; set; }
}
class Program {
    static void Main() {
        var x = new Thing();
        var y = new Thing2();
        new List<IThing<IEnumerable<int>>> { x, y };
    }
}

与显式接口实现相比,这种方法的优点是保证 IThing。Collection和Thing是完全相同的方法。集合,而在显式实现中,它们实际上是不同的方法,所以没有这样的保证。当然,缺点是你必须更明确一点,所以它使代码看起来有点"嘈杂"。

不知道为什么c#编译器不能隐式地找出这个;我的猜测是,如果加上额外的检查,编译时间太长了。

如果你阅读接口的定义,你会注意到它说"…类的相应成员必须是公共的、非静态的,并且具有与接口成员相同的名称和签名。"

当数组或列表实现IEnumerable时,它不是 IEnumerable对象。那是你的问题。

您的签名必须匹配才能生效。您将注意到public List<int> Collection { get; set; }也不起作用。您要么需要更改接口的属性定义,要么让您的实现返回一个IEnumerable <int>,就像您在第二个工作示例中所做的那样。