zoukankan      html  css  js  c++  java
  • 《CLR Via C# 第3版》笔记之(六) IL中的call和callvirt

    C#中调用一个函数时生成的IL代码有两种形式,分别为call 和 callvirt。

    主要内容

    • call和callvirt的区别
    • call和callvirt的例子

    1. call和callvirt的区别

    call的callvirt的区别主要有两点:

    1)call可以调用静态方法,实例方法和虚方法

         callvirt只能调用实例方法和虚方法,不能调用静态方法

    2)call一般是以非虚的方式来调用函数的

         callvirt是以已多态的方式来调用函数的

    2. call和callvirt的例子

    示例代码如下:

    using System;
    
    namespace Test6
    {
        public class CLRviaCSharp_6
        {
            static void Main(string[] args)
            {
                BaseClass.SShow();
    
                BaseClass b = new BaseClass();
                BaseClass s = new SubClass();
                b.VShow();
                s.VShow();
                Console.ReadKey(true);
            }
        }
    
        public class BaseClass
        {
            public static void SShow()
            {
                Console.WriteLine("Base class static method: SShow()!");
            }
    
            public virtual void VShow()
            {
                Console.WriteLine("Base class virtual method: VShow()!");
            }
        }
    
        public class SubClass : BaseClass
        {
            public override void VShow()
            {
                Console.WriteLine("Sub class virtual method: VShow()!");
            }        
        }
    }
    

    程序执行结果为:

    image

    利用ildasm.exe将上面代码生成的exe文件反编译为IL代码。

    命令:ildasm .\Test6.exe /output:Test6.il

    IL代码如下:

    //  Microsoft (R) .NET Framework IL Disassembler.  Version 3.5.30729.1
    //  Copyright (c) Microsoft Corporation.  All rights reserved.
    
    
    
    // Metadata version: v4.0.30319
    .assembly extern mscorlib
    {
      .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
      .ver 4:0:0:0
    }
    .assembly Test6
    {
      .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0C 63 6E 62 6C 6F 67 5F 62 6F 77 65 6E 00   // ...cnblog_bowen.
                                                                                                  00 ) 
      .custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
      .custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
      .custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 18 4C 65 6E 6F 76 6F 20 28 42 65 69 6A 69   // ...Lenovo (Beiji
                                                                                                    6E 67 29 20 4C 69 6D 69 74 65 64 00 00 )          // ng) Limited..
      .custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0C 63 6E 62 6C 6F 67 5F 62 6F 77 65 6E 00   // ...cnblog_bowen.
                                                                                                    00 ) 
      .custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 2A 43 6F 70 79 72 69 67 68 74 20 C2 A9 20   // ..*Copyright .. 
                                                                                                      4C 65 6E 6F 76 6F 20 28 42 65 69 6A 69 6E 67 29   // Lenovo (Beijing)
                                                                                                      20 4C 69 6D 69 74 65 64 20 32 30 31 30 00 00 )    //  Limited 2010..
      .custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 ) 
      .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 ) 
      .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 61 64 61 62 34 66 63 33 2D 33 33 64 35   // ..$adab4fc3-33d5
                                                                                                      2D 34 62 64 30 2D 39 61 32 61 2D 39 35 35 61 65   // -4bd0-9a2a-955ae
                                                                                                      66 38 35 33 31 62 37 00 00 )                      // f8531b7..
      .custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 )             // ...1.0.0.0..
      .custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 29 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B   // ..).NETFramework
                                                                                                            2C 56 65 72 73 69 6F 6E 3D 76 34 2E 30 2C 50 72   // ,Version=v4.0,Pr
                                                                                                            6F 66 69 6C 65 3D 43 6C 69 65 6E 74 01 00 54 0E   // ofile=Client..T.
                                                                                                            14 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61   // .FrameworkDispla
                                                                                                            79 4E 61 6D 65 1F 2E 4E 45 54 20 46 72 61 6D 65   // yName..NET Frame
                                                                                                            77 6F 72 6B 20 34 20 43 6C 69 65 6E 74 20 50 72   // work 4 Client Pr
                                                                                                            6F 66 69 6C 65 )                                  // ofile
    
      // --- The following custom attribute is added automatically, do not uncomment -------
      //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 
    
      .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
      .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                                 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
      .hash algorithm 0x00008004
      .ver 1:0:0:0
    }
    .module Test6.exe
    // MVID: {7020C5F0-2D89-4214-AD2C-E6BFBEC57CA1}
    .imagebase 0x00400000
    .file alignment 0x00000200
    .stackreserve 0x00100000
    .subsystem 0x0003       // WINDOWS_CUI
    .corflags 0x00000003    //  ILONLY 32BITREQUIRED
    // Image base: 0x030F0000
    
    
    // =============== CLASS MEMBERS DECLARATION ===================
    
    .class public auto ansi beforefieldinit Test6.CLRviaCSharp_6
           extends [mscorlib]System.Object
    {
      .method private hidebysig static void  Main(string[] args) cil managed
      {
        .entrypoint
        // Code size       41 (0x29)
        .maxstack  1
        .locals init ([0] class Test6.BaseClass b,
                 [1] class Test6.BaseClass s)
        IL_0000:  nop
        IL_0001:  call       void Test6.BaseClass::SShow()
        IL_0006:  nop
        IL_0007:  newobj     instance void Test6.BaseClass::.ctor()
        IL_000c:  stloc.0
        IL_000d:  newobj     instance void Test6.SubClass::.ctor()
        IL_0012:  stloc.1
        IL_0013:  ldloc.0
        IL_0014:  callvirt   instance void Test6.BaseClass::VShow()
        IL_0019:  nop
        IL_001a:  ldloc.1
        IL_001b:  callvirt   instance void Test6.BaseClass::VShow()
        IL_0020:  nop
        IL_0021:  ldc.i4.1
        IL_0022:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey(bool)
        IL_0027:  pop
        IL_0028:  ret
      } // end of method CLRviaCSharp_6::Main
    
      .method public hidebysig specialname rtspecialname 
              instance void  .ctor() cil managed
      {
        // Code size       7 (0x7)
        .maxstack  8
        IL_0000:  ldarg.0
        IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
        IL_0006:  ret
      } // end of method CLRviaCSharp_6::.ctor
    
    } // end of class Test6.CLRviaCSharp_6
    
    .class public auto ansi beforefieldinit Test6.BaseClass
           extends [mscorlib]System.Object
    {
      .method public hidebysig static void  SShow() cil managed
      {
        // Code size       13 (0xd)
        .maxstack  8
        IL_0000:  nop
        IL_0001:  ldstr      "Base class static method: SShow()!"
        IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
        IL_000b:  nop
        IL_000c:  ret
      } // end of method BaseClass::SShow
    
      .method public hidebysig newslot virtual 
              instance void  VShow() cil managed
      {
        // Code size       13 (0xd)
        .maxstack  8
        IL_0000:  nop
        IL_0001:  ldstr      "Base class virtual method: VShow()!"
        IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
        IL_000b:  nop
        IL_000c:  ret
      } // end of method BaseClass::VShow
    
      .method public hidebysig specialname rtspecialname 
              instance void  .ctor() cil managed
      {
        // Code size       7 (0x7)
        .maxstack  8
        IL_0000:  ldarg.0
        IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
        IL_0006:  ret
      } // end of method BaseClass::.ctor
    
    } // end of class Test6.BaseClass
    
    .class public auto ansi beforefieldinit Test6.SubClass
           extends Test6.BaseClass
    {
      .method public hidebysig virtual instance void 
              VShow() cil managed
      {
        // Code size       13 (0xd)
        .maxstack  8
        IL_0000:  nop
        IL_0001:  ldstr      "Sub class virtual method: VShow()!"
        IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
        IL_000b:  nop
        IL_000c:  ret
      } // end of method SubClass::VShow
    
      .method public hidebysig specialname rtspecialname 
              instance void  .ctor() cil managed
      {
        // Code size       7 (0x7)
        .maxstack  8
        IL_0000:  ldarg.0
        IL_0001:  call       instance void Test6.BaseClass::.ctor()
        IL_0006:  ret
      } // end of method SubClass::.ctor
    
    } // end of class Test6.SubClass
    
    
    // =============================================================
    
    // *********** DISASSEMBLY COMPLETE ***********************
    // WARNING: Created Win32 resource file Test6.res
    

    其中Main函数从63行开始。

    71行的静态方法由call来调用的,78行和81行的虚方法则是由callvirt来调用的。

    为了验证call使用非虚的方式来调用方法的,我们将生成的IL文件Test6.il中81行的callvirt改为call。

    修改Test6.il后保存,然后用ilasm.exe来编译此IL文件为新的exe文件。

    命令:ilasm .\Test6.il /res:Test6.res /output:Test6_new.exe

    然后执行Test6_new.exe,发现最后一步也是调用基类的方法,无法表现出多态性。

    image

    其实我们在写C#代码时并不用关心call和callvirt,c#编译器会帮助我们选择合适的调用方法。

    只是在分析IL时经常会遇到callvirt,这里记录下来方便以后查阅。

  • 相关阅读:
    Python 脚本如何执行另一个脚本
    Yarn集群的搭建、Yarn的架构和WordCount程序在集群提交方式
    Mapreduce概述和WordCount程序
    HDFS及其各组件的机制
    HDFS常用API(2)
    HDFS常用API(1)
    HDFS分布式文件系统的常用命令行操作
    大数据及Hadoop的概述
    谷歌浏览器加载速度慢的解决办法!!!
    Idea中lombok不生效原因
  • 原文地址:https://www.cnblogs.com/wang_yb/p/2092327.html
Copyright © 2011-2022 走看看