是c#和Java的duck类型

本文关键字:duck 类型 Java | 更新日期: 2023-09-27 18:18:57

今天我们有一个奇怪的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都是这样做的,所以这样做似乎有很好的理由。

是c#和Java的duck类型

对于标题中的问题

接口不是Duck Typing.

主格输入:

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

包括Java/c#类和接口。所有类型和类型之间的关系都通过名称定义

结构类型:

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

包括Scala结构类型和c++模板。

Duck Typing :

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

这包括动态类型语言(如Ruby, Python, JavaScript)和c#的dynamic。我也会暂时断言Duck Typing是structtyping的一个子集/非类型化形式;

其他问题

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

因为Close方法是公共的,并且具有一致的签名。由于ConcreteCloser继承自Closer,它也获得了所有的基类方法 -根据继承子类型和Liskov替换原则(不是所有的OOP语言都使用LSP) - ,因此符合ICloseable;然后,它选择通过名称实现ICloseable接口。我不确定这里会有什么警告。

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

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

没有;除非谈论c#中的dynamic。看到上面。

有人能解释一下这背后的语言考虑吗?由于c#和Java都采用相同的方式,因此似乎有很好的理由这样做。

这是由语言设计选择的;接口是在单继承模型中支持指定类型的一种方法。Scala(和Ruby)支持trait;c++支持多重继承。Eiffel在类型级别上支持MI和打破LSP。想想看——没有"唯一正确的路"。

接口是一个契约。该契约声明该类型具有给定签名的方法。不要求在类型本身中定义或重新定义所讨论的成员。

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