且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

《CLR Via C# 第3版》笔记之(六) - IL中的call和callvirt

更新时间:2022-09-17 09:38:12

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

主要内容

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

1. call和callvirt的区别

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

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

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

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

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

2. call和callvirt的例子

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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()!");
        }       
    }
}

程序执行结果为:

《CLR Via C# 第3版》笔记之(六) - IL中的call和callvirt

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

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

IL代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//  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,发现最后一步也是调用基类的方法,无法表现出多态性。

《CLR Via C# 第3版》笔记之(六) - IL中的call和callvirt

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

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



本文转自wang_yb博客园博客,原文链接:http://www.cnblogs.com/wang_yb/archive/2011/06/28/2092327.html,如需转载请自行联系原作者