2011-06-23 30 views
9

Hai khối mã có chức năng giống nhauTrình biên dịch có tối ưu hóa toán tử Null Coalescing khi được sử dụng để tự gán không?

if (myObj == null) 
{ 
    myObj = new MyObj(); 
} 

myObj = myObj ?? new MyObj(); 

Tuy nhiên, là sử dụng toán tử coalescing rỗng làm một bài tập không cần thiết trong trường hợp myObj không phải là null. Nhưng sau đó tôi nghĩ có lẽ trình biên dịch tối ưu hóa các bài tập tự. Có ai biết nếu trình biên dịch sẽ nhận thấy những gì đang xảy ra và về cơ bản chuyển đổi đoạn dưới vào đầu một?

+2

Điều này là hết sức tò mò, tôi nhận ra điều đó là khác nhau một cách không đáng kể. Vui lòng tránh nhận xét "tối ưu hóa sớm" :) – JeremyWeir

+0

Tại sao bạn không kiểm tra bằng [ildasm.exe] (http://msdn.microsoft.com/en-us/library/f7dy01k1 (v = vs.80). aspx)? –

+0

có thể trùng lặp của [does, myval = (someconditon)? someVal: myval được tối ưu hóa để không đặt giá trị trong trường hợp nó sai] (http: // stackoverflow.com/questions/3880114/không-myval-someconditon-someval-myval-get-được tối ưu hóa để không đặt giá trị) – CodeNaked

Trả lời

5

Đối với mục đích so sánh, tôi đã cố gắng biên soạn cả

object myObj = null; 
myObj = myObj ?? new object(); 

object myObj = null; 
if(myObject == null) 
{ 
    myObj = new object(); 
} 

bên trong của phương pháp Main. (Tôi đang sử dụng MonoDevelop 2.4 trên Mono 2.6.7)

Nếu mã được tối ưu hóa như mong đợi, chúng ta sẽ thấy IL tương tự được tạo. Đây là IL cho phiên bản đầu tiên của Main:

.method public static hidebysig 
     default void Main (string[] args) cil managed 
{ 
    .entrypoint 
    .maxstack 3 
    .locals init (
      object V_0) 
    IL_0000: ldnull 
    IL_0001: stloc.0 
    IL_0002: ldloc.0 
    IL_0003: dup 
    IL_0004: brtrue IL_000f 

    IL_0009: pop 
    IL_000a: newobj instance void object::'.ctor'() 
    IL_000f: stloc.0 
    IL_0010: ret 
} 

và cho phiên bản thứ hai:

.method public static hidebysig 
     default void Main (string[] args) cil managed 
{ 
    .entrypoint 
    .maxstack 1 
    .locals init (
      object V_0) 
    IL_0000: ldnull 
    IL_0001: stloc.0 
    IL_0002: ldloc.0 
    IL_0003: brtrue IL_000e 

    IL_0008: newobj instance void object::'.ctor'() 
    IL_000d: stloc.0 
    IL_000e: ret 
} 

Vì vậy, phiên bản đầu tiên (sử dụng toán tử null-coalescing) đã tạo ra hơi nhiều hơn IL.

Nhưng có hai điều cần lưu ý về vấn đề này:

  1. IL Đây là những gì tôi đã sử dụng MoveDevelop - nếu bạn biên dịch nó trong Visual Studio, nó có thể rất tốt đã là một câu chuyện khác nhau. Có lẽ nó được tối ưu hóa trong trình biên dịch của Microsoft. Và thậm chí nếu nó giống với họ, trình biên dịch của người khác có thể dễ dàng tối ưu hóa điều này. Chỉ vì một cái gì đó giữ cho một số trình biên dịch, không có nghĩa là bạn sẽ mong đợi nó từ trình biên dịch của mọi người.
  2. CLR sử dụng JIT. Ngay cả khi điều này không được tối ưu hóa tại thời gian biên dịch, nó có thể sẽ được tối ưu hóa trong thời gian chạy. Trong thực tế, điều này rất có thể là lý do tại sao biên dịch không phải là quá quan tâm đến việc tối ưu hóa vi mô như vậy.
3

Chỉ cần thử nó trong LinqPad:

void Main() 
{ 
    MyObj myObj = null; 
    myObj = myObj ?? new MyObj(); 
} 

này cung cấp cho các IL sau:

IL_0000: ldnull  
IL_0001: stloc.0  
IL_0002: ldloc.0  
IL_0003: dup   
IL_0004: brtrue.s IL_000C 
IL_0006: pop   
IL_0007: newobj  UserQuery+MyObj..ctor 
IL_000C: stloc.0  

Vì vậy, có vẻ như việc chuyển nhượng (stloc.0 tại IL_000C) được thực hiện hay không myObj là vô .. nhưng có lẽ JIT tối ưu hóa điều này sau.

+0

Vì 'myObj' là null, thì tất nhiên nhiệm vụ được thực hiện. Đó là toàn bộ mục đích của toán tử không hợp nhất! –

+0

@Ken, trong trường hợp đó là null, nhưng trình biên dịch không tính đến điều đó ... giá trị có thể đến từ một nơi khác, nó sẽ tạo ra cùng một IL cho 'myObj = myObj ?? new MyObj(); ' –

+0

Xin lỗi vì điều đó. Tôi e là tôi đã hiểu sai ý định của câu hỏi. –

Các vấn đề liên quan