今天,我们用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:
数据类型的兼容性和等效性由显式声明和/或类型名称确定。
这包括Java / C#类和接口。所有类型以及类型之间的关系均由名称定义。
Structural Typing:
..兼容性和等效性由类型的实际结构或定义确定,而不由其他特征(例如名称或声明位置)确定。
这包括Scala Structural Types和C++模板。
Duck Typing:
..对象的方法和属性确定有效的语义。
这包括动态类型的语言(例如Ruby,Python,JavaScript)和C#的dynamic
。我还想断言鸭式打字是结构式打字的子集/无类型形式。它与名词性键入正交。
对于其他问题
为什么编译器接受Closer.close()方法作为接口方法的实现?
因为Close方法是公共的并且具有一致的签名。由于ConcreteCloser继承自Closer,因此它还获得了所有基类方法-每个Inheritance Subtyping和Liskov Substitution Principle(并非所有OOP语言都使用LSP),因此符合ICloseable。然后选择按名称实现ICloseable接口。我不确定在这里会收到什么警告。
如果C#是结构化(或Duck)类型的,则可以使用Closer代替ICloseable,但是不能; ICloseable c = new Closer()
无效,因为Closer未定义为与ICloseable名义相关。
对我而言,在这种情况下,C#和Java有点鸭式化。
没有;除非在C#中谈论dynamic
,否则不会这样。往上看。
有人可以向我解释其背后的语言注意事项吗?由于C#和Java都以相同的方式进行操作,因此似乎有充分的理由。
这是根据语言设计选择的;接口是在单继承模型中支持命名键入的一种方法。 Scala(和Ruby)支持Traits; C++支持多重继承。 Eiffel支持MI并在类型级别上中断LSP。走吧,没有“正确的道路”。