【问题标题】:Is C# and Java duck-typed?C# 和 Java 是鸭子类型的吗?
【发布时间】:2013-06-17 18:06:42
【问题描述】:

今天,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 中都没有一个警告 和日食?

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

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

【问题讨论】:

  • 关闭投票给离题?为什么?
  • 附带说明:.net 也有“动态”,它确实允许基本上是鸭式打字。但是,这与接口完全无关(本例)。
  • @nawfal 你介意推荐一个更好的吗?这只是我试图传达对我来说“错误”的地方。

标签: c# java inheritance interface duck-typing


【解决方案1】:

对于标题中的问题

接口不是 Duck Typing。

Nominative Typing:

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

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

Structural Typing:

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

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

Duck Typing:

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

这包括动态类型语言(例如 Ruby、Python、JavaScript)和 C# 的 dynamic。我还暂时断言 Duck Typing 是 Structural Typing 的子集/无类型形式;它与主格类型正交。

其他问题

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

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

如果 C# 是 Structurally(或 Duck)类型的,那么 Closer 可以用来代替 ICloseable,但它不能;ICloseable c = new Closer() 是无效的,因为 Closer 没有被定义为 主格 相关的 ICloseable。

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

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

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

这是由语言设计选择;接口是在 单一继承 模型中支持主称类型的一种方法。 Scala(和 Ruby)支持 Traits; C++ 支持多重继承。 Eiffel 支持 MI 并在类型级别上打破 LSP。去想 - 没有“唯一正确的方法”。

【讨论】:

  • 感谢您的全面回答!
【解决方案2】:

接口是一个合约。该合同声明该类型具有给定签名的方法。不需要在类型本身中定义或重新定义相关成员。

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

【讨论】:

  • 我不认为 Duck Typing 暗示成员在编译时没有被解析,尽管我只真正看到了动态类型语言中使用的术语并且我无法在 Java/C# 中提供“术语使用的反例示例”。
  • @user2246674 是的,可能有更好的表述方式。它实际上不是定义的正式部分,只是该术语在某些上下文中的常见含义。
  • 是的,我想这就是我挂断电话的地方。在实际使用中,这是有道理的,但是.. 可能不是这样吗?可能只是接受的名称更改(例如 Scala 中的结构类型),具体取决于其他含义。
  • 感谢您的回答!我明白这里发生了什么,但我真的很想知道为什么会这样处理。认为这也容易出错。
  • @user2246674 是的,可以。想到的最好的例子是 C++ 模板。从技术上讲,它在编译时执行验证,但它并没有验证模板类型是否总是给定的类型,只是它具有给定的操作。
猜你喜欢
  • 2013-06-06
  • 1970-01-01
  • 2010-11-07
  • 1970-01-01
  • 2018-10-11
  • 2011-05-18
  • 1970-01-01
  • 2020-09-30
  • 1970-01-01
相关资源
最近更新 更多