2012-02-27 30 views
7

Tôi đã tạo phương thức C# trong studio trực quan chỉ chứa một câu lệnh chuyển đổi trong đó mỗi trường hợp trả về một giá trị. Theo thói quen cá nhân, tôi đặt một cái gì đó tương tự như mã sau đây:C# Tuyên bố chuyển đổi: Hiệu quả hơn để không sử dụng mặc định?

private string SwitchMethod(int num) 
    { 
     switch (num) 
     { 
      case 0: 
       return "result 1"; 
      case 1: 
       return "result 2"; 
      case 2: 
       return "result 3"; 
     } 
     return "no result"; 
    } 

Câu hỏi của tôi là: Mã nào sẽ có hiệu suất tốt hơn? Mã trên hoặc dưới, hoặc giống nhau? Và tại sao?

Tôi cho rằng vì tối ưu hóa trình biên dịch ... chúng có thể chỉ giống nhau ... nhưng tôi thực sự không biết.

private string SwitchMethod(int num) 
    { 
     switch (num) 
     { 
      case 0: 
       return "result 1"; 
      case 1: 
       return "result 2"; 
      case 2: 
       return "result 3"; 
      default: 
       return "no result"; 
     } 
    } 

RÀ SOÁT: Dường như tôi nên cụ thể hơn: Khi biên soạn ... sẽ mã ít hiệu quả được tạo ra bởi một hay khác?

Tôi nhận thấy rằng sự khác biệt về hiệu suất có thể không đáng kể ... Tôi thực sự tò mò.

+4

Điều này khá chủ quan. Tôi tránh có nhiều điểm thoát khỏi một phương thức hoặc hàm, nhưng YMMV. Nếu bạn thực sự tò mò, hãy xem IL. –

+1

Đã biên soạn? Tôi không ở phía trước trình biên dịch của tôi, nhưng tôi gần như chắc chắn là một mặc định là bắt buộc. –

+0

Ném một ngoại lệ cho biết "không nên đến đây" cho mặc định nếu bạn thực sự nghĩ rằng nó sẽ không xảy ra – Matt

Trả lời

9
public static string foo(int num) 
     { 
      switch (num) 
      { 
       case 0: 
        return "result 1"; 
       case 1: 
        return "result 2"; 
       case 2: 
        return "result 3"; 
      } 
      return "no result"; 
     } 

trở thành:

.method public hidebysig static string foo(int32 num) cil managed 
{ 
    // Code size  57 (0x39) 
    .maxstack 1 
    .locals init ([0] string CS$1$0000, 
      [1] int32 CS$4$0001) 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: stloc.1 
    IL_0003: ldloc.1 
    IL_0004: switch  ( 
         IL_0017, 
         IL_001f, 
         IL_0027) 
    IL_0015: br.s  IL_002f 
    IL_0017: ldstr  "result 1" 
    IL_001c: stloc.0 
    IL_001d: br.s  IL_0037 
    IL_001f: ldstr  "result 2" 
    IL_0024: stloc.0 
    IL_0025: br.s  IL_0037 
    IL_0027: ldstr  "result 3" 
    IL_002c: stloc.0 
    IL_002d: br.s  IL_0037 
    IL_002f: ldstr  "no result" 
    IL_0034: stloc.0 
    IL_0035: br.s  IL_0037 
    IL_0037: ldloc.0 
    IL_0038: ret 
} // end of method Program::foo 

Moving sự trở lại vào một trường hợp mặc định:

.method public hidebysig static string foo(int32 num) cil managed 
{ 
    // Code size  57 (0x39) 
    .maxstack 1 
    .locals init ([0] string CS$1$0000, 
      [1] int32 CS$4$0001) 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: stloc.1 
    IL_0003: ldloc.1 
    IL_0004: switch  ( 
         IL_0017, 
         IL_001f, 
         IL_0027) 
    IL_0015: br.s  IL_002f 
    IL_0017: ldstr  "result 1" 
    IL_001c: stloc.0 
    IL_001d: br.s  IL_0037 
    IL_001f: ldstr  "result 2" 
    IL_0024: stloc.0 
    IL_0025: br.s  IL_0037 
    IL_0027: ldstr  "result 3" 
    IL_002c: stloc.0 
    IL_002d: br.s  IL_0037 
    IL_002f: ldstr  "result 4" 
    IL_0034: stloc.0 
    IL_0035: br.s  IL_0037 
    IL_0037: ldloc.0 
    IL_0038: ret 
} // end of method Program::foo 

Chính xác như vậy. Không có sự khác biệt về hiệu suất. Tôi đã thay đổi "không có kết quả" thành kết quả 4 chỉ để đảm bảo mã đã được tạo lại. Rõ ràng trình biên dịch C# tối ưu hóa nó hoặc nó chỉ kết thúc là tương đương.

+0

Cảm ơn rất nhiều! Tha thứ cho sự thiếu hiểu biết của tôi ... nhưng bạn đã sử dụng cái gì để tạo ra hội đồng? – bsara

+2

@Brandon Có rất nhiều. Ví dụ: ilspy –

+2

* ILDasm * đi kèm với .NET Framework SDK. Hãy ghi nhớ đây là Mã hội IL mà không phải là những gì CPU nhìn thấy. Bạn có thể sử dụng một công cụ cũng đi kèm với SDK NGen.exe để tạo ra hội đồng đó, nhưng nó có khả năng tối ưu hóa nó một cách khác nhau tùy thuộc vào phần cứng. –

4

Thực hành tốt là luôn bao gồm trường hợp mặc định tại chân của nút chuyển cho các trường hợp không có trường hợp nào khác hợp lệ. Đây không phải là một vấn đề hiệu quả bởi vì nếu một trong các trường hợp trước bị trúng - chương trình của bạn sẽ không kiểm tra bất kỳ trường hợp nào khác (nó tương đương với việc sử dụng if/else if/else - nơi khác là mặc định) .

Hy vọng điều này sẽ hữu ích.

+0

Câu trả lời của bạn là ok, nhưng bạn nên cẩn thận trong việc lấy ý nghĩa của bạn bằng cách tương đương: http://stackoverflow.com/questions/445067/if-vs-switch-speed –

+0

Nhưng khi nào biên dịch ... sẽ nhiều mã được tạo ra bởi một hay khác? Do đó dẫn đến nhiều hướng dẫn hơn được thực hiện khi không có điều kiện mong đợi nào được đáp ứng? – bsara

+0

Mã khác không phải lúc nào cũng kém hiệu quả. –

3

Thay vì một hàm và câu lệnh chuyển đổi, bạn sẽ tốt hơn với một từ điển chung, trong đó khóa là KofaxEnvironment và giá trị giống như những gì bạn đang quay trở lại từ công tắc. Một cái gì đó như:

Dictionary<KofaxEnvironment, string> 

hoặc

Dictionary<int, string> 

Tôi cũng sẽ không lo lắng về hiệu suất. Sự đúng đắn nên là mục tiêu đầu tiên của bạn.

Nhưng, nếu bạn gắn bó với một công tắc sử dụng mặc định mà ném một ngoại lệ:

default: 
    throw new ArgumentException("Serious programmer error!"); 

Và như đối với hiệu suất, chênh lệch (nếu có ở tất cả) giữa một mặc định chuyển đổi và rơi qua một lợi nhuận sẽ không đáng kể.

+0

Đó không phải là chính xác những gì tôi đã nhận được ... nhưng đó là một ý tưởng tuyệt vời ... Tôi chắc chắn sẽ sử dụng nó trong tương lai. Nhiều mã sạch hơn! – bsara

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