new & override 不完全PK

从一段简单的代码开始:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    
class A
    {
        
public virtual void Call()
        { Console.WriteLine(
"this is class A"); }
    }

    
class B : A
    {
        
public new void Call()
        { Console.WriteLine(
"this is class B"); }
    }

    
class C : A
    {
        
public override void Call()
        { Console.WriteLine(
"this is class C"); }
        
public  void Call2()
        { Console.WriteLine(
"this is class C"); }
    }

    
class Program
    {
        
static void Main(string[] args)
        {
            
//情况1
            A a1 = new B();
            A a2 
= new C();
            a1.Call();
            a2.Call();

            
//情况2
            B a3 = new B();
            a3.Call();

            
//情况3
            C a4 = new C();
            a4.Call();
            a4.Call2();

            Console.ReadLine();
        }
    }
}

试问这点代码的执行结果是什么?


Why?从IL来看:

.method private hidebysig static void  Main(string[] args) cil managed
{
  
.entrypoint
  
// 代码大小    & nbsp;  67 (0x43)
  .maxstack  1
  
.locals init ([0class ConsoleApplication1.A a1,
           [
1class ConsoleApplication1.A a2,
           [
2class ConsoleApplication1.B a3,
           [
3class ConsoleApplication1.C a4)
  
IL_0000:  nop
  
IL_0001:  newobj     instance void ConsoleApplication1.B::.ctor()
  
IL_0006:  stloc.0
  
IL_0007:  newobj     instance void ConsoleApplication1.C::.ctor()
  
IL_000c:  stloc.1
  
IL_000d:  ldloc.0
  
IL_000e:  callvirt   instance void ConsoleApplication1.A::Call()
  
IL_0013:  nop
  
IL_0014:  ldloc.1
  
IL_0015:  callvirt   instance void ConsoleApplication1.A::Call()
  
IL_001a:  nop
  
IL_001b:  newobj     instance void ConsoleApplication1.B::.ctor()
  
IL_0020:  stloc.2
  
IL_0021:  ldloc.2
  
IL_0022:  callvirt   instance void ConsoleApplication1.B::Call()
  
IL_0027:  nop
  
IL_0028:  newobj     instance void ConsoleApplication1.C::.ctor()
  
IL_002d:  stloc.3
  
IL_002e:  ldloc.3
  
IL_002f:  callvirt   instance void ConsoleApplication1.A::Call()
  
IL_0034:  nop
  
IL_0035:  ldloc.3
  
IL_0036:  callvirt   instance void ConsoleApplication1.C::Call2()
  
IL_003b:  nop
  
IL_003c:  call       string [mscorlib]System.Console::ReadLine()
  
IL_0041:  pop
  
IL_0042:  ret
// end of method Program::Main

不完全结论是:

情况1时,a1.Call()和a2.Call()的IL代码都是callvirt   instance void ConsoleApplication1.A::Call(),但是不同的是,a1.Call()结果是this is class Aa2.Call()结果是this is class C,为什么呢?因为B类里是public new void Call(),而C类里是public override void Call()

情况2,没什么可说的,貌似一切正常!

情况3,有点意思了,a4.Call() 对应得IL是callvirt   instance void ConsoleApplication1.A::Call(),而结果却是this is class C,为什么呢?a4.Call2()也是貌似一切正常。

综合上面的几种情况,我们可以得出如下结论,从情况2和 a4.Call2()表现一致来看,使用new的作用跟完全重新声明一个新方法没什么区别;从情况1里的a2.Call()和情况3里的a4.Call()表现一致来看,a.生成IL代码的时候,如果调用的方法在父类里存在,且在子类里覆盖了这个方法,那么不管声明的引用变量是父类(情况1)还是子类(情况3),生成的IL代码都是调用父类的方法(callvirt   instance void ConsoleApplication1.A::Call());b.运行时CLR执行顺序是从父类到子类(从上到下),如果父类的方法是虚方法,则去子类里找是否有子类覆盖了这个方法,没有则还是执行父类里的方法,如果有就执行子类里的方法;

以上这些只是即兴做了一个简单对比,只是推测不是标准答案,而且应该很不完全,欢迎大家补充。

---------------------------------------------------------------------------------------

如上所述,上面这些只是一个粗浅的推断,勉强自圆其说而已,已经有园友给出了更深入的研究,
请大家参考3楼精彩的文章:http://blog.csdn.net/fuadam/archive/2008/08/25/2827561.aspx
posted @ 2008-09-01 23:19  Justin  阅读(2043)  评论(5编辑  收藏  举报