When an instance method is called,
a check is performed at runtime to ensure the current object pointer is not null
. This is representd by the
callvirt
instruction in the
IL
.
instance.cs
class Testv2 {
public string Hello() {
return "Hello";
}
}
class Program {
public static void main() {
var a = new Testv2();
var result = a.Hello();
}
}
subset of IL for instance.cs
.class private auto ansi beforefieldinit Testv2
extends [System.Runtime]System.Object
{
// Methods
.method public hidebysig
instance string Hello () cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
// Method begins at RVA 0x2050
// Code size 11 (0xb)
.maxstack 1
.locals init (
[0] string
)
IL_0000: nop
IL_0001: ldstr "Hello"
IL_0006: stloc.0
IL_0007: br.s IL_0009
IL_0009: ldloc.0
IL_000a: ret
} // end of method Testv2::Hello
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2067
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Testv2::.ctor
} // end of class Testv2
.class private auto ansi beforefieldinit Program
extends [System.Runtime]System.Object
{
// Methods
.method public hidebysig static
void main () cil managed
{
// Method begins at RVA 0x2070
// Code size 15 (0xf)
.maxstack 1
.locals init (
[0] class Testv2 a,
[1] string result
)
IL_0000: nop
IL_0001: newobj instance void Testv2::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: callvirt instance string Testv2::Hello()
IL_000d: stloc.1
IL_000e: ret
} // end of method Program::main
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2067
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor
} // end of class Program
When a static method is called, this null check is skipped.
static.cs
static class Test {
public static string Hello() {
return "Hello";
}
}
class Program {
public static void main() {
var result = Test.Hello();
}
}
subset of IL for static.cs
.class private auto ansi abstract sealed beforefieldinit Test
extends [System.Runtime]System.Object
{
// Methods
.method public hidebysig static
string Hello () cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
// Method begins at RVA 0x2050
// Code size 11 (0xb)
.maxstack 1
.locals init (
[0] string
)
IL_0000: nop
IL_0001: ldstr "Hello"
IL_0006: stloc.0
IL_0007: br.s IL_0009
IL_0009: ldloc.0
IL_000a: ret
} // end of method Test::Hello
} // end of class Test
.class private auto ansi beforefieldinit Program
extends [System.Runtime]System.Object
{
// Methods
.method public hidebysig static
void main () cil managed
{
// Method begins at RVA 0x2068
// Code size 8 (0x8)
.maxstack 1
.locals init (
[0] string result
)
IL_0000: nop
IL_0001: call string Test::Hello()
IL_0006: stloc.0
IL_0007: ret
} // end of method Program::main
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x207c
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor
} // end of class Program
The IL is generated from Sharplab .