Examinons le code MSIL généré pour la méthode générique suivante:compilateur C# + code générique avec la boxe + contraintes
public static U BoxValue<T, U>(T value)
where T : struct, U
where U : class
{
return value;
}
Rechercher:
.method public hidebysig static !!U BoxValue<valuetype .ctor
([mscorlib]System.ValueType, !!U) T,class U>(!!T 'value') cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: box !!T
IL_0006: unbox.any !!U
IL_000b: ret
}
Mais pour le code générique ci-dessus, l'IL plus efficace la représentation doit être:
IL_0000: ldarg.0
IL_0001: box !!T
IL_0006: ret
Il est connu à partir des contraintes que la valeur est encadré dans type de référence. Unbox.any
L'opcode est complètement redondant car après l'opcode box
la valeur à IL stack sera déjà une référence valide à !!U
, qui peut être utilisée sans aucun déballage.
Pourquoi le compilateur C# 3.0 n'utilise pas de métadonnées de contraintes pour émettre du code générique plus efficace? Unbox.any donne un petit overhead (juste 4x-5x plus lent), mais pourquoi ne pas émettre un meilleur code dans ce scénario?
Tous les types d'interface, 'System.Object',' System.ValueType' (et type 'System.Enum', mais C# ne supporte pas les contraintes d'énumération) – ControlFlow
Ces contraintes semblent étranges, mais elles sont absolument dites que * type T a une conversion implicite en type U * et cette conversion est * conversion en boxe *. – ControlFlow