Почему медленнее сравнивать тип значения, допускающий значение NULL, с типом NULL об универсальном методе без ограничений?

Я столкнулся с очень забавной ситуацией, когда сравнение типа, допускающего значение NULL, с типом NULL внутри универсального метода происходит в 234 раза медленнее, чем сравнение типа значения или ссылочного типа. Код выглядит следующим образом:

static bool IsNull<T>(T instance)
{
    return instance == null;
}

Код выполнения:

int? a = 0;
string b = "A";
int c = 0;

var watch = Stopwatch.StartNew();

for (int i = 0; i < 1000000; i++)
{
    var r1 = IsNull(a);
}

Console.WriteLine(watch.Elapsed.ToString());

watch.Restart();

for (int i = 0; i < 1000000; i++)
{
    var r2 = IsNull(b);
}

Console.WriteLine(watch.Elapsed.ToString());

watch.Restart();

for (int i = 0; i < 1000000; i++)
{
    var r3 = IsNull(c);
}

watch.Stop();

Console.WriteLine(watch.Elapsed.ToString());
Console.ReadKey();

Вывод для приведенного выше кода:

00: 00: 00.1879827

00: 00: 00.0008779

00: 00: 00.0008532

Как видите, сравнение nullable int с null выполняется В 234 раза медленнее, чем при сравнении типа int или строки. Если я добавлю вторую перегрузку с правильными ограничениями, результаты резко изменятся:

static bool IsNull<T>(T? instance) where T : struct
{
    return instance == null;
}

Теперь результаты следующие:

00: 00: 00.0006040

00: 00: 00.0006017

00: 00: 00.0006014

Это почему? Я не проверял байтовый код, потому что я не владею им свободно, но даже если бы байтовый код был немного другим, я ожидал бы, что JIT оптимизирует это, а это не так (я использую оптимизацию) .

13
задан Diego Frata 18 April 2011 в 19:26
поделиться