在外部库中绑定到基本方法的方法无法处理“之间”的新虚拟方法

假设我有一个库1.0.0版,其中包含以下内容:

public class Class1 { public virtual void Test() { Console.WriteLine( "Library:Class1 - Test" ); Console.WriteLine( "" ); } } public class Class2 : Class1 { } 

我在控制台应用程序中引用此库,其中包含以下内容:

 class Program { static void Main( string[] args ) { var c3 = new Class3(); c3.Test(); Console.ReadKey(); } } public class Class3 : ClassLibrary1.Class2 { public override void Test() { Console.WriteLine("Console:Class3 - Test"); base.Test(); } } 

运行该程序将输出以下内容:

 Console:Class3 - Test Library:Class1 - Test 

如果我构建一个新版本的库,版本2.0.0,看起来像这样:

 public class Class1 { public virtual void Test() { Console.WriteLine( "Library:Class1 - Test V2" ); Console.WriteLine( "" ); } } public class Class2 : Class1 { public override void Test() { Console.WriteLine("Library:Class2 - Test V2"); base.Test(); } } 

并将此版本复制到包含我的控制台程序的bin文件夹并运行它,结果是:

 Console:Class3 - Test Library:Class1 - Test V2 

即,从不执行Class2.Test方法,Class3.Test中的base.Test调用似乎绑定到Class1.Test,因为在编译控制台程序时Class2.Test不存在。 这对我来说非常令人惊讶,如果您在不重新编译应用程序的情况下部署新版本的库,则可能会成为一个大问题。

有没有其他人有这方面的经验?

有什么好的解决方案吗?

这使得很容易添加只调用base的空覆盖,以防我将来需要在该级别添加一些代码…

编辑:

似乎已确定调用在编译时绑定到第一个现有的基本方法。 我想知道为什么。 如果我构建我的控制台程序时引用我的库的第2版(这应该意味着编译调用以调用Class2.Test)然后将bin文件夹中的dll替换为版本1,结果是,如预期的那样:

 Console:Class3 - Test Library:Class1 - Test 

因此,当Class2.Test不存在时,没有运行时错误。 为什么基本调用不能编译为首先调用Class2.Test?

从Eric Lippert或使用编译器的其他人那里得到评论会很有意思……

这是3月29日我博客的主题:

http://blogs.msdn.com/ericlippert/archive/2010/03/29/putting-a-base-in-the-middle.aspx

事实certificate,C#1.0是按照你的方式做到的,而且这个决定会导致一些有趣的崩溃和性能问题。 我们将它改为C#2.0中的新方式。

我从这个问题中学到了很多东西。 有关详细信息,请参阅博客

当我用库的第一个版本构建可执行文件时(我将其命名为“Thing”),并将其反汇编,我得到:

 L_000d: call instance void [Thing]Thing.Class1::Test() 

使用引用的新DLL重建它:

 L_000d: call instance void [Thing]Thing.Class2::Test() 

这样就可以确认引用哪个方法的决定是编译时的。