为什么这个C#代码返回它所做的
有人可以帮我理解为什么这段代码片段返回“Bar-Bar-Quux”? 即使阅读了界面,我也很难理解这一点。
interface IFoo { string GetName(); } class Bar : IFoo { public string GetName() { return "Bar"; } } class Baz : Bar { public new string GetName() { return "Baz"; } } class Quux : Bar, IFoo { public new string GetName() { return "Quux"; } } class Program { static void Main() { Bar f1 = new Baz(); IFoo f2 = new Baz(); IFoo f3 = new Quux(); Console.WriteLine(f1.GetName() + "-" + f2.GetName() + "-" + f3.GetName()); } } 
	
这里发生了两件事情。 一个是成员隐藏。 这是相当知名的,并在其他地方报道。 另一个鲜为人知的特性是C#5规范第13.4.6节中介绍的接口重新实现。 去引用:
允许inheritance接口实现的类通过将接口包含在基类列表中来重新实现该接口。 接口的重新实现遵循与接口的初始实现完全相同的接口映射规则。 因此,inheritance的接口映射对为重新实现接口而build立的接口映射没有任何影响。
和
inheritance的公共成员声明和inheritance的显式接口成员声明参与重新实现的接口的接口映射过程。
  f1.GetName()的结果是“Bar”,因为Baz.GetName方法隐藏Bar.GetName而f1被声明为Bartypes。 除非明确声明为虚拟和重写,否则不会向运行时types的实现发送调度。 
 同样,对于f2.GetName() , Baz.GetName在Bar隐藏了实现,所以在通过对接口的引用使用dispatch时不会被调用。 接口被“映射”到在Bar声明的方法,因为这是接口被声明的types。  Baz有一个相同名称的兼容方法并不重要。 接口映射规则在规范的第13.4.4节中定义。 如果GetName已经在Bar被声明为虚拟的,它可以被覆盖,然后通过接口被调用。 结果也是“酒吧”。 
 对于f3.GetName() , Quux重新实现了IFoo因此它可以将自己的映射定义为GetName 。 请注意,它也隐藏了从Barinheritance的实现。 没有必要使用new来重新执行,只是简单地隐藏了关于隐藏的警告。 所以结果是“Quux”。 
这就解释了你看到的输出:“Bar-Bar-Quux”
Eric Lippert的这篇文章讨论了这个棘手的function中的一些细微差别。
 接口根据定义没有相关的实现,也就是说他们的方法总是虚拟的和抽象的。 相反,上面的类Bar定义了GetName的具体实现。 这符合实施IFoo所需的合同。 
  Baz类现在inheritanceBar并声明一个new方法GetName 。 也就是说父类Bar有一个名字相同的方法,但是在明确使用Baz对象的时候它是完全被忽略的。 
 但是,如果一个Baz对象被转换为一个Bar ,或者简单地分配给一个Bar或IFootypes的variables,它将会按照它的操作行为,并像Bar 。 换句话说,方法名GetName引用Bar.GetName而不是Baz.GetName 。 
 现在,在第三种情况下, Quux从Barinheritance并实现IFoo 。 现在,当作为一个IFoo ,它将提供自己的实现(根据Mike Z的答案中提供的规范)。 
当一个Quux被当作一个酒吧时,它会返回“Bar”,就像Baz所做的那样。
由于在Console.WriteLine方法调用中对GetName()的3次调用,输出是Bar-Bar-Quux。
 Bar f1 = new Baz(); IFoo f2 = new Baz(); IFoo f3 = new Quux(); Console.WriteLine(f1.GetName() + "-" + f2.GetName() + "-" + f3.GetName()); //Bar-Bar-Quux 
让我们来看看每个电话,这样可以更清楚地发生什么事情。
f1.GetName()
  f1被实例化为Baz 。  但是 ,它被input为Bar 。 因为Bar暴露了GetName ,所以当使用f1.GetName()时,这就是被调用的方法 – 不pipe Baz实现了GetName 。 原因是f1不是键入为Baz ,如果是,它会调用Baz的GetName方法。 这方面的一个例子将是检查的输出 
 Console.WriteLine(((Baz)f1).GetName() + "-" + f2.GetName() + "-" + f3.GetName()); //Baz-Bar-Quux 
 这是可能的,因为两个事实。 首先, f1最初被实例化为Baz ,它被简单地键入为Bar 。 其次, Baz 确实有一个GetName方法,并且在其定义中使用new隐藏inheritance的Bar的GetName方法,允许调用Baz的GetName 。 
f2.GetName()
 一个非常相似的键入与f2发生,被定义为 
 IFoo f2 = new Baz(); 
 虽然Baz类实现了一个GetName方法,但它并没有实现IFoo的GetName方法,因为Baz不能从IFooinheritance,因此该方法不可用。  Bar实现IFoo ,并且由于Baz从Barinheritance, Bar的GetName是在f2types为IFoo时暴露的方法。 
 再一次,因为f2最初被实例化为Baz ,它仍然可以投给Baz 。 
 Console.WriteLine(f1.GetName() + "-" + ((Baz)f2).GetName() + "-" + f3.GetName()); //Bar-Baz-Quux 
 并将有相同的输出结果为上述原因f1 ( f2最初键入为Baz ,和Baz的GetName方法隐藏inheritanceBar的GetName方法)。 
f3.GetName()
 这里有不同的故事  Quuxinheritance并实现了IFoo , 并通过使用new隐藏了Bar的IFoo实现。 结果是Quux的GetName方法就是被调用的方法。