为什么必须明确实现此接口?

Mar*_*eIV 12 c# interface

几年后回到C#所以我有点生疏了.遇到这个(简化的)代码,它让我头疼.

为什么必须明确实现该IDataItem.Children属性?普通Children房产不满足要求吗?毕竟,该属性直接用于满足它.为什么不隐含?

public interface IDataItem {

    IEnumerable<string> Children { get; }
}

public class DataItem : IDataItem {

    public Collection<string> Children { get; } = new Collection<string>();

    // Why doesn't 'Children' above implement this automatically?!
    // After all it's used directly to satisfy the requirement!
    IEnumerable<string> IDataItem.Children => Children;
}
Run Code Online (Sandbox Code Playgroud)

根据C#源代码,这里的定义是Collection<T>:

[System.Runtime.InteropServices.ComVisible(false)]
public class Collection<T> :
    System.Collections.Generic.ICollection<T>,
    System.Collections.Generic.IEnumerable<T>, <-- Right Here
    System.Collections.Generic.IList<T>,
    System.Collections.Generic.IReadOnlyCollection<T>,
    System.Collections.Generic.IReadOnlyList<T>,
    System.Collections.IList
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,它明确地实现了,IEnumerable<T>并且从我的理解,如果'X'实现'Y'然后'X' 'Y',所以Collection<String> 一个IEnumerable<String>所以我不确定为什么它不满意.

Dam*_*ver 6

也许这个例子让它更清晰.我们希望签名完全匹配1,2,不允许任何替换,尽管类型之间存在任何继承关系.

我们不允许写这个:

public interface IDataItem {

    void DoStuff(string value);
}

public class DataItem : IDataItem {

    public void DoStuff(object value) { }
}
Run Code Online (Sandbox Code Playgroud)

你的例子是相同的,除了你要求返回类型而不是参数(并采用缩小而不是加宽转换,原因很明显).尽管如此,同样的原则也适用.在匹配签名时,类型必须完全匹配3.

您可以要求提供允许此类事件发生的语言,并且可能存在此类语言.但事实是,这些是C#的规则.


1除了涉及泛型和接口/ delgates的Co和Contra-variance的一些有限支持之外.

2有些人可能会争论签名是否是在这里使用的正确词汇,因为在这种情况下,返回类型与参数类型,通用arity等一样重要; 在大多数其他人谈论C#方法签名的情况下,他们将明确忽略返回类型,因为他们(明确地或隐含地)考虑重载规则所说的内容,并且对于重载,返回类型不是签名的一部分.

尽管如此,我对我在这里使用"签名"一词感到满意.签名未在C#规范中正式定义,并且在使用它的地方,通常会指出签名的哪些部分被考虑用于重载.

3更不用说如果你的Children方法返回了一个struct实现的问题,那么会引发的问题IEnumerable<string>.现在你有了一个返回值类型值和调用者的方法(通过IDataItem希望接收对象引用的接口).

因此,该方法甚至不能按原样使用.我们必须(在这种情况下)隐藏装箱转换来实现接口.当推测C#的这一部分时,我相信它们不会为你自己可以轻易编写的代码提供太多"隐藏的魔力".


Jle*_*HeP 5

在您的示例中,您的"普通"Children属性实际上并不满足接口要求.类型不同.你可以施展它并不重要 - 它们是不同的.

类似的例子,也许更明显的是,如果你将实现一个接口,其实际方法返回IEnumerable并尝试从实际类中的ICollection方法.仍然存在编译时错误.

正如@Ben Voigt所说,转换仍会产生一些代码,如果你想拥有它 - 你需要隐式添加它.