C#和Java是鸭子吗?

时间:2013-06-17 18:06:42

标签: c# java inheritance interface duck-typing

今天我们用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都以同样的方式执行,因此似乎有充分的理由。

2 个答案:

答案 0 :(得分:2)

界面是合约。该合同规定该类型具有给定签名的方法。不需要在类型本身中定义或重新定义相关成员。

这与鸭子打字无关。鸭子打字意味着成员在编译时没有得到解决;它们在运行时被解决了。在这里,编译器能够确定该类在编译时实现方法

答案 1 :(得分:2)

对于标题中的问题

接口不是Duck Typing。

Nominative Typing

  

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

这包括Java / C#类和接口。类型之间的所有类型和关系都按名称​​定义

Structural Typing

  

..兼容性和等同性由类型的实际结构或定义决定,而不是由其名称或声明地点等其他特征决定。

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

Duck Typing

  

..对象的方法和属性决定了有效的语义

这包括动态类型语言(例如Ruby,Python,JavaScript)和C#的dynamic。我还试探性地断言Duck Typing是结构类型的子集/无类型形式;它与Nominative Typing正交。

其他问题

  

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

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

如果C#在结构上(或鸭子)键入,则可以使用Closer代替ICloseable,但它不能; ICloseable c = new Closer()无效,因为Closer未被定义为主要相关的ICloseable。

  

对我而言,C#和Java在这种情况下有些低级。

没有;除非在C#中谈论dynamic。见上文。

  

有人可以解释一下背后的语言因素吗?由于C#和Java都以同样的方式执行,因此似乎有充分的理由。

这是通过语言设计选择;接口是支持单一继承模型中的命名类型的一种方法。 Scala(和Ruby)支持Traits; C ++支持多重继承。 Eiffel支持MI并且还在类型级别破坏LSP。去图 - 没有“正确的方法”。