今天,我们用close()方法发生了一件奇怪的事情。

这是有疑问的代码:

interface ICloseable
{
    void Close();
}

public class Closer
{
    public void Close()
    {
        Console.WriteLine("closed");
    }
}

public class ConcreteCloser : Closer, ICloseable
{
}


class Program
{
    static void Main(string[] args)
    {
        var concrete = new ConcreteCloser();
        concrete.Close();
        Console.ReadKey();
    }
}

所以问题是:

基类不实现该接口。

为什么编译器接受Closer.close()方法作为实现
接口方法?


为什么两个Visual C#2010 Professional中都至少没有警告
和Eclipse?

对我来说,在这种情况下,C#和Java有点像鸭子。

有人可以向我解释其背后的语言注意事项吗?
由于C#和Java都以相同的方式进行操作,因此似乎有充分的理由。

最佳答案

对于标题中的问题

接口不是鸭式输入。

Nominative Typing:

数据类型的兼容性和等效性由显式声明和/或类型名称确定。

这包括Java / C#类和接口。所有类型以及类型之间的关系均由名称定义。

Structural Typing:

..兼容性和等效性由类型的实际结构或定义确定,而不由其他特征(例如名称或声明位置)确定。

这包括Scala Structural Types和C++模板。

Duck Typing:

..对象的方法和属性确定有效的语义。

这包括动态类型的语言(例如Ruby,Python,JavaScript)和C#的dynamic。我还想断言鸭式打字是结构式打字的子集/无类型形式。它与名词性键入正交。

对于其他问题

为什么编译器接受Closer.close()方法作为接口方法的实现?

因为Close方法是公共的并且具有一致的签名。由于ConcreteCloser继承自Closer,因此它还获得了所有基类方法-每个Inheritance SubtypingLiskov Substitution Principle(并非所有OOP语言都使用LSP),因此符合ICloseable。然后选择按名称实现ICloseable接口。我不确定在这里会收到什么警告。

如果C#是结构化(或Duck)类型的,则可以使用Closer代替ICloseable,但是不能; ICloseable c = new Closer()无效,因为Closer未定义为与ICloseable名义相关。

对我而言,在这种情况下,C#和Java有点鸭式化。

没有;除非在C#中谈论dynamic,否则不会这样。往上看。

有人可以向我解释其背后的语言注意事项吗?由于C#和Java都以相同的方式进行操作,因此似乎有充分的理由。

这是根据语言设计选择的;接口是在单继承模型中支持命名键入的一种方法。 Scala(和Ruby)支持Traits; C++支持多重继承。 Eiffel支持MI并在类型级别上中断LSP。走吧,没有“正确的道路”。

07-24 09:34