2010-09-28 25 views
7

Theo tài liệu hướng dẫn trên lớp ConditionalAttribute:Có phải ConditionalAttribute phải loại bỏ toàn bộ các dòng hoặc chỉ các cuộc gọi phương thức?

Áp dụng ConditionalAttribute cho một phương pháp chỉ để trình biên dịch rằng một cuộc gọi phương pháp này sẽ không sử biên dịch vào Microsoft trung ngôn ngữ (MSIL) trừ khi có điều kiện biểu tượng biên dịch được liên kết với ConditionalAttribute được định nghĩa.

Với tôi điều này nói rằng thuộc tính Conditional chỉ thay đổi hành vi ở cấp độ cuộc gọi phương thức riêng lẻ. Nhưng xem xét các đoạn mã sau:

class InstanceType 
{ 
    public InstanceType DoSideEffects() 
    { 
     Console.WriteLine("Side effects!"); 
     return this; 
    } 

    public InstanceType DoMoreSideEffects() 
    { 
     Console.WriteLine("More side effects!"); 
     return this; 
    } 

    [Conditional("DEBUG")] 
    public void ConditionalMethod() 
    { 
     Console.WriteLine("Conditional method run."); 
    } 
} 

class Program 
{ 
    static void Main() 
    { 
     var x = new InstanceType(); 

     // The compiler appears to strip out this entire line 
     // in a Release build. 
     x.DoSideEffects().DoMoreSideEffects().ConditionalMethod(); 

     var y = new InstanceType(); 

     // When each method call appears on its own line, 
     // the first two methods are included as expected. 
     y.DoSideEffects(); 
     y.DoMoreSideEffects(); 
     y.ConditionalMethod(); 
    } 
} 

Hãy so sánh các kết quả đầu ra của Debug và phát hành xây dựng:

 
DEBUG     RELEASE 
Side effects!   Side effects! 
More side effects!  More side effects! 
Conditional method run. 
Side effects! 
More side effects! 
Conditional method run. 

là hành vi này quy định ở đâu đó? Tôi đã nghĩ rằng cả hai bản dựng được cho là có cùng đầu ra ngoại trừ các dòng đọc "Chạy phương thức có điều kiện".

+0

sự hiểu biết của tôi về '[Conditional]' cũng giống như bạn, và Tôi nghĩ rằng bạn đang thấy hiệu quả của một tối ưu hóa diễn ra ở đây. IL trông như thế nào trong chế độ phát hành? –

+0

Thú vị đủ, ngay cả Visual Studio (hoặc là nó ReSharper?) Màu sắc toàn bộ dòng màu xám/không sử dụng trong trường hợp đầu tiên, nếu bạn không xác định DEBUG. Trong khi thứ hai, nó chỉ màu sắc cuộc gọi đến ConditionalMethod() màu xám/không sử dụng. –

+0

bản sao có thể có của [Tại sao thuộc tính có điều kiện của Thuộc tính .NET bị loại bỏ?] (Http://stackoverflow.com/questions/410865/why-does-nets-conditional-attribute-cause-side-effects-to -be-removed) –

Trả lời

2

Tính năng ghép nối :-) Tôi chưa bao giờ nhận thấy điều đó.

Tôi đã xem xét IL. Điều này không giải thích được hành vi (quá trình biên dịch), nhưng nó vẫn ghi lại kết quả, tôi tin.

Cả C# code dòng rõ ràng là trái ra trong IL:

  • Trong biên soạn DEBUG một đối tượng mới được tạo ra (biến x), lưu trữ tại vị trí 0 và tải. Sau đó trong ba phương pháp được áp dụng liên tiếp: DoSideEffects(), DeMoreSideEffects(), và ConditionalMethod()
  • Trong biên soạn CHÍ ​​biến vẫn được tạo ra, nhưng vì nó là không cần thiết, nó sẽ ngay lập tức pop'ed . Thay vào đó, biến y được lưu trữ tại vị trí 0 và được nạp.

Với tôi, điều này trông giống như một lỗi, thực sự. Dường như nó đã có thể chỉ có thể loại trừ các ConditionalMethod() gọi trong IL. Nhưng có vẻ như bạn đúng, toàn bộ dòng đó bị bỏ đi.

// DEBUG compilation 
.method private hidebysig static void Main() cil managed 
{ 
    .entrypoint 
    // Code size  58 (0x3a) 
    .maxstack 1 
    .locals init (class ConsoleApplication3.InstanceType V_0, 
      class ConsoleApplication3.InstanceType V_1) 
    IL_0000: nop 
    IL_0001: newobj  instance void ConsoleApplication3.InstanceType::.ctor() 
    IL_0006: stloc.0 
    IL_0007: ldloc.0 
    IL_0008: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoSideEffects() 
    IL_000d: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoMoreSideEffects() 
    IL_0012: callvirt instance void ConsoleApplication3.InstanceType::ConditionalMethod() 
    IL_0017: nop 
    IL_0018: newobj  instance void ConsoleApplication3.InstanceType::.ctor() 
    IL_001d: stloc.1 
    IL_001e: ldloc.1 
    IL_001f: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoSideEffects() 
    IL_0024: pop 
    IL_0025: ldloc.1 
    IL_0026: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoMoreSideEffects() 
    IL_002b: pop 
    IL_002c: ldloc.1 
    IL_002d: callvirt instance void ConsoleApplication3.InstanceType::ConditionalMethod() 
    IL_0032: nop 
    IL_0033: call  valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() 
    IL_0038: pop 
    IL_0039: ret 
} // end of method Program::Main 

// RELEASE compilation 
.method private hidebysig static void Main() cil managed 
{ 
    .entrypoint 
    // Code size  33 (0x21) 
    .maxstack 1 
    .locals init ([0] class ConsoleApplication3.InstanceType y) 
    IL_0000: newobj  instance void ConsoleApplication3.InstanceType::.ctor() 
    IL_0005: pop 
    IL_0006: newobj  instance void ConsoleApplication3.InstanceType::.ctor() 
    IL_000b: stloc.0 
    IL_000c: ldloc.0 
    IL_000d: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoSideEffects() 
    IL_0012: pop 
    IL_0013: ldloc.0 
    IL_0014: callvirt instance class ConsoleApplication3.InstanceType ConsoleApplication3.InstanceType::DoMoreSideEffects() 
    IL_0019: pop 
    IL_001a: call  valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() 
    IL_001f: pop 
    IL_0020: ret 
} // end of method Program::Main 
0

Xin lỗi kéo lên một bài đăng cũ, nhưng tôi vừa gặp phải điều tương tự và đây là cuộc thảo luận duy nhất về vấn đề này mà tôi có thể tìm thấy.

Tôi có linh cảm về những gì đang diễn ra. [Conditional] đang tước cuộc gọi tới ConditionalMethod()cũng như bất kỳ biểu thức nào hoạt động như thông số được truyền cho nó (theo tài liệu và chuỗi khác được liên kết ở trên).

Tôi đoán là tham số ngụ ý this đang được xử lý chính xác theo cùng một cách. Trong dòng x.DoSideEffects().DoMoreSideEffects().ConditionalMethod(); biểu thức được chuyển thành thisx.DoSideEffects().DoMoreSideEffects() được loại bỏ cẩn thận, loại bỏ các tác dụng phụ.

Nếu chúng ta viết lại vào mã giả mà chúng tôi vượt qua một cách rõ ràng this như tham số đầu tiên cho mỗi phương pháp nó trở nên rõ ràng hơn nhiều:

ConditionalMethod(DoMoreSideEffects(DoSideEffects(x)));

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