2011-09-21 33 views
10

Để chuyển đổi chuỗi thành enum, cách nào sau đây tốt hơn?Enum.Parse() hoặc Switch

  1. Mã này:

    colorEnum color = (colorEnum)Enum.Parse(typeof(colorEnum), "Green"); 
    
  2. hay này:

    string colorString = ... 
    colorEnum color;   
    switch (colorString) 
    { 
        case "Green": 
         color = colorEnum.Green; 
         break; 
        case "Red": 
         color = colorEnum.Red; 
         break; 
        case "Orange": 
         color = colorEnum.Orange; 
         break; 
        .... 
    } 
    
+0

Tôi nghĩ bạn không thể bật các chuỗi. –

+4

@Ramon: Bạn sai - trong C#, chúng tôi luôn có thể bật chuỗi. –

+0

@Ramon: Tất nhiên bạn có thể. –

Trả lời

8

Bạn nên sử dụng Enum.TryParse, nếu nó không thành công, bạn có thể xử lý các lỗi một cách chính xác.

mẫu:

 ColorsEnum colorValue; 
    if (Enum.TryParse(colorString, out colorValue))   
     if (Enum.IsDefined(typeof(Colors), colorValue) | colorValue.ToString().Contains(",")) 
      Console.WriteLine("Converted '{0}' to {1}.", colorString, colorValue.ToString()); 
     else 
      Console.WriteLine("{0} is not an underlying value of the Colors enumeration.", colorString); 
    else 
     Console.WriteLine("{0} is not a member of the Colors enumeration.", colorString); 
+0

Lưu ý rằng Enum.TryParse chỉ có sẵn trên .Net 4.0 –

+2

Và có những nhược điểm khác cho Enum.TryParse - xem câu trả lời. –

2

1) là tốt hơn nhiều. Đó là mã sạch hơn. Bạn đang làm trong một dòng những gì sẽ mất nhiều trong 2). Ngoài ra, nó ít bị lỗi. Khi bạn thêm một mục khác vào colorEnum, bạn sẽ cần phải nhớ mở rộng 2) máy ảnh 1) sẽ hoạt động.

Bạn cũng có thể muốn xử lý lỗi trên Enum.Parse.

+1

và sau đó ai đó quyết định cho bạn chuỗi "0" .. – harold

4

Và còn Enum.TryParse<TEnum> thì sao?

string myColorStr = "red"; 
colorEnum myColor; 
if(!Enum.TryParse<colorEnum>(myColorStr, true, out myColor)) 
{ 
    throw new InvalidOperationException("Unknown color " + myColorStr); 
} 
7

(Cảnh báo: bao gồm các plug cho thư viện mã nguồn mở của riêng tôi ...)

Cá nhân tôi muốn sử dụng Unconstrained Melody, mà kết thúc với mã typesafe sạch hơn và nhiều hơn nữa:

ColorEnum color = Enums.ParseName<ColorEnum>(text); 

Bạn có thể sử dụng TryParseName nếu bạn nghi ngờ nó có thể không hợp lệ. Rõ ràng điều này đòi hỏi một thư viện mở rộng, nhưng hy vọng bạn sẽ tìm thấy những điều khác trong đó hữu ích quá :)

Enum.TryParse từ NET 4 là tốt hơn so với khác được xây dựng trong tùy chọn, nhưng:

  • Bạn thắng không bắt các loại không enum lúc biên dịch, ví dụ Enum.TryParse<int>(...) sẽ vẫn biên dịch; Không bị giới hạn Melody thực sự chỉ cho phép các loại enum
  • Enum.TryParse cũng sẽ phân tích "1" (hoặc bất kỳ giá trị số là khi chuyển đổi sang một chuỗi) - nếu bạn thực sự chỉ mong đợi tên, tôi nghĩ rằng nó tốt hơn để chỉ chấp nhận tên

tôi chắc chắn sẽ không bật các giá trị chuỗi - nó có nghĩa là nếu bạn đổi tên các giá trị enum, bạn phải nhớ để đặt lại tên cho giá trị trường hợp là tốt.

+0

+1 Greate one. –

+0

Vì tất cả các phương thức trên Enums.cs bị ràng buộc giống nhau, bạn có thể không thể hiện nó như là một ràng buộc lớp (và có thể đặt tên nó là 'Enum '), hoặc không hoạt động (hoặc có lý do nào đó) đang tránh điều đó)? –

+0

@Damien: Vâng, các phương pháp mở rộng không thể ở trong một lớp học chung chung. I * có thể * có khả năng có một lớp cho các phương thức mở rộng và một lớp cho các phương thức không mở rộng ... nhưng tôi không chắc chắn nó sẽ tạo ra nhiều sự khác biệt. –

1

khác so với thực tế là hai đoạn mã khác nhau không làm điều tương tự, tôi muốn sử dụng này:

colorEnum color; 
if (!colorEnum.TryParse(colorString, true, out color) 
    color = colorEnum.Green; // Or whatever default value you wish to have. 

Nếu bạn không có .NET 4.0 sau đó tôi muốn làm một cái gì đó như thế này:

public static TEnum ToEnum<TEnum>(this string strEnumValue, TEnum defaultValue) 
{ 
    if (!Enum.IsDefined(typeof(TEnum), strEnumValue)) 
     return defaultValue; 

    return (TEnum)Enum.Parse(typeof(TEnum), strEnumValue); 
} 

Đây là một Extension Method-string.

0

Tôi thấy biến thể chuyển đổi khủng khiếp vì bạn sẽ phải sửa đổi công tắc mỗi khi bạn thay đổi enum.

Tôi thích sử dụng TryParse thuộc về enum của bạn. Vì vậy, bạn có thể sử dụng nó như thế này

string colorString = ..... 
colorEnum color; 

colorEnum.TryParse(colorString, out color); 

Hoặc nếu bạn không quan tâm đến trường hợp của chuỗi

colorEnum.TryParse(colorString, true, out color); 

Các returnValue của TryParse là true nếu chuỗi là một enum hợp lệ, false nếu không phải.

2

Số 1 chỉ đơn giản là về khả năng đọc và bảo trì. Nếu bạn mở rộng enum, bạn cần phải thực hiện thêm công việc, wheras with 2 bạn phải thêm nhiều trường hợp hơn vào câu lệnh switch

0

Trên quan điểm hiệu suất, vì enums được thực hiện dưới dạng trường tĩnh, phương pháp phân tích cú pháp có thể kết thúc lên làm refection trên enum loại sau đó và thử một phương pháp GetField mà có thể nhanh hơn so với trường hợp. Ở đầu kia, nếu 90% trường hợp, màu xanh lục, trường hợp sẽ rất nhanh ... Lưu ý rằng CLR đôi khi sắp xếp lại mã nội bộ, thay đổi thứ tự của vụ án dựa trên thống kê (thực ra, tôi không chắc chắn nó làm điều đó nhưng doc tuyên bố nó có thể).

+3

ngược lại, phản xạ chậm như mật đường và chuyển đổi nhanh - chuyển đổi trên chuỗi được thực thi như một từ điển để chuyển đổi chuỗi thành số nguyên, và sau đó là một công tắc dày đặc bình thường, không liên quan gì đến thống kê vì nó là một bảng nhảy không "IF tuyến tính" mà * không được sử dụng anyway *, trình biên dịch tạo ra một "cây IF và một số công tắc cho các phần dày đặc" - đó là tất nhiên một chi tiết thực hiện – harold

+0

@harold: cảm ơn – VdesmedT

2

Vì bạn đã thêm thẻ 'hiệu suất', tôi sẽ chuyển sang nút gạt.
Có, bạn sẽ phải thay đổi các trường hợp khi bạn đổi tên/thêm/xóa mọi thứ trong enum. Vậy thì quá tệ rồi. Bất kỳ biến thể nào của Enum.Parse/TryParse đều sử dụng rất nhiều mã lạ và một số phản ánh, chỉ cần nhìn vào bên trong hàm với ILSpy hoặc như vậy. Sau đó, cũng có vấn đề chấp nhận "-12354" và thậm chí cả danh sách các tên hợp lệ được phân cách bằng dấu phẩy (kết quả là tất cả chúng cùng nhau) ngay cả khi enum không có thuộc tính [Flags].

Thay vào đó, bạn có thể tạo từ điển dịch tên enum thành giá trị. Nó thực sự phải nhanh hơn chuyển đổi, bởi vì một chuyển đổi trên dây cũng đi qua một từ điển nhưng bạn lưu một phần chuyển đổi thực tế.

Rõ ràng cả hai cách đều tốn một số chi phí bảo trì hơn enum.parse và các biến thể; cho dù đó là giá trị nó là lên đến bạn, vì tất cả chúng ta chỉ có bạn có đủ kiến ​​thức về dự án để thực hiện giao dịch hiệu suất/thời gian mã hóa.

0

Tôi sử dụng những điều sau đây, nó giúp bạn có được sự an toàn về loại trong khi vẫn không giảm khi bạn thêm giá trị mới vào Enum, nó cũng rất nhanh.

public static colorEnum? GetColorFromString(string colorString) 
{ 
    colorEnum? retVal = null; 
    if(Enum.IsDefined(typeof(colorEnum), colorString)) 
     retVal = (colorEnum)Enum.Parse(typeof(colorEnum), colorString); 
    return retVal; 
} 

Thử nghiệm của tôi với 8 mục trong enum cho thấy cách này nhanh hơn phương pháp chuyển đổi.

Hoặc nếu không bạn có thể sử dụng (cách rất chậm):

public static colorEnum? GetColorFromString(string colorString) 
{ 
    foreach (colorEnum col in Enum.GetValues(typeof(colorEnum))) 
    { 
     if (col.ToString().Equals(colorString)) 
     { 
      return col; 
     } 
    } 
    return null; 
} 
1

Cá nhân, trong khi tôi hoàn toàn tốt với các giải pháp Enum.Parse cho các kịch bản không thực hiện (đọc: một off chạy chức năng này đôi khi ... và có rất nhiều kịch bản như vậy để chắc chắn), tôi không thể đếm ngược suy nghĩ có thể liên quan đến một số phương pháp kiểu phản chiếu khi hàm này cần được thực hiện trong vòng lặp trên hàng trăm/nghìn cộng với giá trị enum cùng một lúc.Gack!

Vì vậy, giải pháp sau đây là một trong những giải pháp tốt nhất của cả hai thế giới.

Chỉ truy xuất tất cả các giá trị của enum lúc khởi động hoặc không, bất cứ khi nào nó hoạt động tốt nhất cho bạn (dưới đây là một cách để làm điều đó), và sau đó xây dựng một từ điển với chúng.

private static Dictionary<string, Color> colorDictionary; 
    public static Dictionary<string, Color> ColorDictionary 
    { 
     get 
     { 
      if (colorDictionary== null) { 
       colorDictionary = new Dictionary<string, Color>(); 
       var all = Enum.GetValues(typeof(Color)).OfType<Color>(); 
       foreach (var val in all) 
        dict.Add(val.ToString(), val); 
      } 
      return colorDictionary; 
     } 
    }