.NET object creation, whats faster?

后端 未结 4 626
醉酒成梦
醉酒成梦 2020-12-04 00:26

IS there a difference between those 2 ways of object creation?

new MyClass() { Id = 1, Code = \"Test\" };

or

MyClass c = ne         


        
4条回答
  •  情书的邮戳
    2020-12-04 00:45

    The second will possibly be almost certainly insignificantly faster, because there's one fewer assignment involved, logically. In the first case, the code is actually equivalent to:

    MyClass tmp = new MyClass()
    tmp.Id = 1;
    tmp.Code = "Test";
    MyClass c = tmp;
    

    It's very possible that the JIT compiler will elide these as you're declaring a new variable - it wouldn't be able to do so if you were assigning to an existing variable with an object initializer.

    EDIT: I've just tried compiling with and without optimizations turned on, and in this "new variable" case the C# compiler elides the two if it's optimizing. It doesn't otherwise (but the JIT still could). In the "reassignment" case it could make an observable difference, so I wouldn't expect the same optimization. I haven't checked though.

    I would be very surprised to see a situation where it actually made a significant difference though, so I'd go with the more readable option, which IMO is the first.

    EDIT: I thought folks might be interested in a benchmark showing it making a difference. This is deliberately horrible code to make the hidden extra assignment slow - I've created a big, mutable struct. Urgh. Anyway...

    using System;
    using System.Diagnostics;
    
    struct BigStruct
    {
        public int value;
        #pragma warning disable 0169
        decimal a1, a2, a3, a4, a5, a6, a7, a8;
        decimal b1, b2, b3, b4, b5, b6, b7, b8;
        decimal c1, c2, c3, c4, c5, c6, c7, c8;
        decimal d1, d2, d3, d4, d5, d6, d7, d8;
        #pragma warning restore 0169
    }
    
    class Test
    {
        const int Iterations = 10000000;
    
        static void Main()
        {
            Time(NewVariableObjectInitializer);
            Time(ExistingVariableObjectInitializer);
            Time(NewVariableDirectSetting);
            Time(ExistingVariableDirectSetting);
        }
    
        static void Time(Func action)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            action();
            stopwatch.Stop();
            Console.WriteLine("{0}: {1}ms",
                              action.Method.Name,
                              stopwatch.ElapsedMilliseconds);
        }
    
        static int NewVariableObjectInitializer()
        {
            int total = 0;
            for (int i = 0; i < Iterations; i++)
            {
                BigStruct b = new BigStruct { value = i };
                total += b.value;
            }
            return total;
        }
    
        static int ExistingVariableObjectInitializer()
        {
            int total = 0;
            BigStruct b;
            for (int i = 0; i < Iterations; i++)
            {
                b = new BigStruct { value = i };
                total += b.value;
            }
            return total;
        }
    
        static int NewVariableDirectSetting()
        {
            int total = 0;
            for (int i = 0; i < Iterations; i++)
            {
                BigStruct b = new BigStruct();
                b.value = i;
                total += b.value;
            }
            return total;
        }
    
        static int ExistingVariableDirectSetting()
        {
            int total = 0;
            BigStruct b;
            for (int i = 0; i < Iterations; i++)
            {
                b = new BigStruct();
                b.value = i;
                total += b.value;
            }
            return total;
        }
    }
    

    Results (with /o+ /debug-):

    NewVariableObjectInitializer: 3328ms
    ExistingVariableObjectInitializer: 3300ms
    NewVariableDirectSetting: 1464ms
    ExistingVariableDirectSetting: 1491ms
    

    I'm somewhat surprised that the NewVariableObjectInitializer version is slower than the direct setting ones... it looks like the C# compiler doesn't optimize this case in the way that it does for reference types. I suspect there's some subtlety around value types that prevents it.

提交回复
热议问题