C#和Java是鸭式的吗?

提问

今天,我们使用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

.. compatibility and equivalence of data types is determined by explicit declarations and/or the name of the types.

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

Structural Typing

.. compatibility and equivalence are determined by the type’s actual structure or definition, and not by other characteristics such as its name or place of declaration.

这包括Scala Structural Types和C模板.

Duck Typing

.. object’s methods and properties determine the valid semantics.

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

对于其他问题

Why does the compiler accept the Closer.close() method as implementation of the interface method?

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

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

For me, C# and Java, are somewhat ducktyped in this case.

没有;除非谈论C#中的动态.往上看.

Can someone explain me the language considerations behind that please? As both C# and Java do it the same way, there seem to be good reasons for that.

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