CIL unbox_any инструкция - странное поведение
.method public static void Test<class T>(object A_0) cil managed
{
// Code size 13 (0xd)
.maxstack 1
.locals init (!!T V_0)
IL_0000: ldarg.0
IL_0001: isinst !!T
IL_0006: unbox.any !!T
IL_000b: stloc.0
IL_000c: ret
} // end of method DemoType::Test
Код C# равен:
public static void Test<T>(object o) where T : class
{
T t = o as T;
}
Мои вопросы:
Почему unbox.any звонили? если вы просто делаете
var a = father as child
вызовет isinst intruction, а unbox.any не вызовет, и если я удалю обобщенное определение и попытаюсь привести (isinst) объект к какому-либо классу, unbox.any вызываться не будет.
Может быть, unbox.any был вызван из-за общего определения, поэтому в этом случае unbox.any нужно вызвать исключение NullReferenceException, потому что ответ инструкции isinst возвращает null для этого приведения. смотрите unbox_any. И если вы попытаетесь запустить этот код, вы увидите, что не возникло никаких исключений.
Обновить
Я могу понять unbox_any, потому что параметр типа объекта, и он пытается привести его к конкретному типу после проверки isinst. Может быть, дженерики влияют также.
Мой вопрос: почему бы не выдать исключение в unbox.any, если объект, который мы пытаемся распаковать в T, равен нулю?
Документация гласит: "NullReferenceException выбрасывается, если obj является пустой ссылкой".
1 ответ
Распаковка должна держать проверяющего счастливым. Верификатор не особенно умел знать, что параметр типа T всегда будет ссылочным типом, и поэтому компилятор C# выдает эти ненужные в противном случае распаковки.
Если вы выполните поиск исходного кода Roslyn для Unbox_any и IsVerifierReference, вы увидите, что это происходит во многих местах вокруг генератора кода.
При создании кода дрожание будет знать, является ли параметр типа ссылкой или нет, и должно генерировать приличный код независимо от, казалось бы, ненужной инструкции.