Reputation: 18239
I have the following method:
public static bool EquivalentTo<T>(this T? current, T? compare)
where T : class
{
if (current is null && compare is null)
// both are null
return true;
if (current is null || compare is null)
// one is null, but not both
return false;
return current.Equals(compare);
}
IL Spy gives the following IL in Release build:
.method public hidebysig static
bool EquivalentTo<class T> (
!!T current,
!!T compare
) cil managed aggressiveinlining
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
01 00 00 00
)
.param type T
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 01 00 00
)
// Method begins at RVA 0x4971
// Header size: 1
// Code size: 54 (0x36)
.maxstack 8
IL_0000: ldarg.0
IL_0001: box !!T
IL_0006: brtrue.s IL_0012
IL_0008: ldarg.1
IL_0009: box !!T
IL_000e: brtrue.s IL_0012
IL_0010: ldc.i4.1
IL_0011: ret
IL_0012: ldarg.0
IL_0013: box !!T
IL_0018: brfalse.s IL_0022
IL_001a: ldarg.1
IL_001b: box !!T
IL_0020: brtrue.s IL_0024
IL_0022: ldc.i4.0
IL_0023: ret
IL_0024: ldarg.0
IL_0025: box !!T
IL_002a: ldarg.1
IL_002b: box !!T
IL_0030: callvirt instance bool [System.Runtime]System.Object::Equals(object)
IL_0035: ret
} // end of method Extensions::EquivalentTo
I compiled with Visual Studio 2022 and .Net 8.0.100-preview.7.23376.3
in 64-bit.
I don't understand why there is boxing when the generic type is constrained to a class
and thus cannot be a value type. What am I missing?
Upvotes: 1
Views: 55
Reputation: 71544
box !!T
br.true
or br.false
sequence is always a no-op for structs.
Since the JITter compiles separate code for all struct (valuetype) generic code, it can see that a box would never result in a null, so it is elided. In the case of classes (reference types) it just does a normal null check.
You can see this if you look at the JIT ASM machine code that is generated for both structs and classes.
Upvotes: 2