将struct转换为对象以进行null比较不会导致装箱?

naw*_*fal 7 c# performance boxing casting nullable

我做了一些基准测试时遇到了这个问题.

bool b;
MyStruct s;
for (int i = 0; i < 10000000; i++)
{
    b = (object)s == null;
}
Run Code Online (Sandbox Code Playgroud)

调试:200毫秒

发布:5毫秒

bool b;
MyStruct? s = null;
for (int i = 0; i < 10000000; i++)
{
    b = (object)s == null;
}
Run Code Online (Sandbox Code Playgroud)

调试:800毫秒

发布:800毫秒

我可以理解这个结果,因为转换可为空的结构给object了我一个盒装类型的结构.但是为什么不进行转换struct sobject进行空比较(如在第一种方法中)导致相同的性能?编译器是否正在优化调用以返回,false因为结构不能为null?

Mat*_*son 8

是的,编译器正在优化它.

它知道struct永远不能为null,因此将它转换为对象的结果永远不会为null - 因此它将b在第一个示例中设置为false.事实上,如果你使用Resharper,它会警告你表达式总是假的.

对于第二个当然,可以为空的null可以为空,因此必须进行检查.

(您还可以使用Reflector检查编译器生成的IL代码来验证这一点.)

原始测试代码并不好,因为编译器知道可空结构将始终为null,因此也会优化掉该循环.不仅如此,在发布版本中,编译器实现了b未使用的优化并优化了整个循环.

为了防止这种情况,并显示更真实的代码会发生什么,请测试它:

using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            bool b = true;
            MyStruct? s1 = getNullableStruct();
            Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < 10000000; i++)
            {
                b &= (object)s1 == null; // Note: Redundant cast to object.
            }

            Console.WriteLine(sw.Elapsed);

            MyStruct s2 = getStruct();
            sw.Restart();

            for (int i = 0; i < 10000000; i++)
            {
                b &= (object)s2 == null;
            }

            Console.WriteLine(sw.Elapsed);
        }

        private static MyStruct? getNullableStruct()
        {
            return null;
        }

        private static MyStruct getStruct()
        {
            return new MyStruct();
        }
    }

    public struct MyStruct {}
}
Run Code Online (Sandbox Code Playgroud)