是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都是这样做的,所以这样做似乎有很好的理由。
对于标题中的问题
接口不是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类型意味着在编译时不解析成员;它们在运行时被解析。在这里,编译器能够确定类在编译时实现了方法。