2010-08-26 29 views
8
class Program 
{ 
    static void Main(string[] args) 
    { 
     string value = "12345"; 
     Type enumType = typeof(Fruits); 
     Fruits fruit = Fruits.Apple; 
     try 
     { 
      fruit = (Fruits) Enum.Parse(enumType, value); 
     } 
     catch (ArgumentException) 
     { 
      Console.WriteLine(String.Format("{0} is no healthy food.", value)); 
     } 
     Console.WriteLine(String.Format("You should eat at least one {0} per day.", fruit)); 
     Console.ReadKey(); 
    } 

    public enum Fruits 
    { 
     Apple, 
     Banana, 
     Orange 
    } 
} 

Nếu bạn thực thi mã trên kết quả cho thấy:Tại sao Enum.Parse tạo các mục không xác định?

Bạn nên ăn ít nhất một 12345 mỗi ngày.

Tôi thực sự mong đợi một ArgumentException sẽ bị ném nếu không biết tên (chuỗi) được chuyển. Lấy một cái nhìn cận cảnh định nghĩa Enum.Parse tiết lộ:

Tóm tắt:
Chuyển đổi chuỗi đại diện của tên hoặc giá trị số của một hoặc liệt kê nhiều hằng cho một đối tượng tương đương liệt kê.

Exceptions:
ArgumentException: enumType không phải là một Enum. - hoặc - giá trị là một chuỗi rỗng hoặc chỉ chứa khoảng trắng. -hoặc- giá trị là một tên, nhưng không phải là một trong các hằng số được đặt tên được xác định cho điều tra.

I.e. nếu một biểu diễn chuỗi của một số nguyên được truyền, một giá trị enum mới được tạo ra và bây giờ ngoại lệ được ném bởi thiết kế. Điều này có nghĩa không?

Ít nhất bây giờ tôi biết phải gọi Enum.IsDefined(enumType, value) trước Enum.Parse()

+1

Đây có phải là câu hỏi không? –

+0

Tại sao bạn hỏi và trả lời câu hỏi của riêng bạn? –

+0

Câu hỏi được đặt ra về hành vi ... – Markus

Trả lời

4

"Hằng số được đặt tên" là biểu diễn văn bản của giá trị của một giá trị của Enum, không phải là số mà bạn đã gán cho nó.

Nếu bạn thay đổi:

string value = "12345"; 

Để:

string value = "Cake"; 

Bạn sẽ thấy lỗi mà bạn đang mong đợi, bởi vì "giá trị là một cái tên, nhưng không phải một trong những hằng số có tên định nghĩa cho việc liệt kê. Trong trường hợp này, giá trị bạn đang chuyển vào một tên, "Bánh", nhưng không phải là giá trị trong liệt kê.

Hãy suy nghĩ về Enum.Parse(enumType, value); làm như sau:

  1. Nếu value là một tham chiếu null, ném một ArgumentNullException
  2. Là giá trị trong value một trong những hằng số có tên trong kiểu liệt kê trong enumType. Nếu có, hãy trả lại giá trị đó từ việc liệt kê và dừng.
  3. Giá trị trong value có thể chuyển đổi trực tiếp thành loại cơ bản (trong trường hợp này là Int32), nếu có, trả về giá trị đó và dừng lại (ngay cả khi không có hằng số được đặt tên cho giá trị đó).
  4. Giá trị trong value có thể chuyển đổi trực tiếp thành loại cơ bản hay không, nhưng nằm ngoài phạm vi của loại cơ bản? ví dụ. giá trị là một chuỗi chứa số một lớn hơn MAXINT. Nếu có, hãy ném một số OverflowException.
  5. Giá trị không thể chuyển sang loại cơ bản? Nếu có, hãy ném một ArgumentException.
+0

Bạn nói đúng, vì Enum là một Int32 Enum.Parse ("") là đúng khi trả lại một giá trị hợp lệ. Vấn đề của tôi là do nhìn thấy Enum như một Int32 bị ràng buộc mà trên thực tế thì không. – Markus

+0

Đây không phải là, nói đúng, chính xác. Một chuỗi không bao giờ "có thể chuyển" thành một int, nó yêu cầu một chuyển đổi có thể thông qua một loạt các phương thức ('Convert.ToInt32',' int.Parse', 'int.TryParse', v.v.). Biểu thức chính xác hơn của 3.) sẽ là "Giá trị trong' value' có thể chuyển đổi trực tiếp * thành kiểu cơ bản (trong trường hợp này 'Int32') không? Nếu có, trả về giá trị đó và dừng (** ngay cả khi không có hằng số có tên cho giá trị đó **) –

+0

@Adam, điểm công bằng, tôi đã thay đổi câu trả lời của mình cho phù hợp =) – Rob

0

Bạn cần phải sử dụng Enum.IsDefined:

http://msdn.microsoft.com/en-us/library/essfb559.aspx

using System; 

    [Flags] enum Colors { None=0, Red = 1, Green = 2, Blue = 4 }; 

    public class Example 
    { 
     public static void Main() 
     { 
      string[] colorStrings = { "0", "2", "8", "blue", "Blue", "Yellow", "Red, Green" }; 
      foreach (string colorString in colorStrings) 
      { 
      try { 
       Colors colorValue = (Colors) Enum.Parse(typeof(Colors), colorString);   
       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); 
      } 
      catch (ArgumentException) { 
       Console.WriteLine("'{0}' is not a member of the Colors enumeration.", colorString); 
      } 
      } 
     } 
    } 
    // The example displays the following output: 
    //  Converted '0' to None. 
    //  Converted '2' to Green. 
    //  8 is not an underlying value of the Colors enumeration. 
    //  'blue' is not a member of the Colors enumeration. 
    //  Converted 'Blue' to Blue. 
    //  'Yellow' is not a member of the Colors enumeration. 
    //  Converted 'Red, Green' to Red, Green. 
+0

Ông ấy đã nói rằng trong câu hỏi của mình :) –

+0

Vâng tôi biết, nhưng tôi không hiểu tại sao Enum.Parse tạo ra các giá trị mới , nó giống như gọi Int.Parse ("số lớn không được biết đến nhân loại") và nhận được một kết quả ... – Markus

0

Cá nhân tôi nghĩ rằng đó là một điều đáng tiếc rằng Enum.Parse chấp nhận chuỗi đại diện của một số. Nếu bạn đang tìm kiếm một giải pháp thay thế, bạn có thể muốn xem dự án Unconstrained Melody của mình có các tùy chọn phân tích cú pháp khác nhau và được nhập mạnh mẽ.

Bạn chắc chắn có thể sử dụng Enum.IsDefined cùng với phân tích cú pháp. Bạn có chắc chắn muốn chấp nhận các phiên bản chuỗi số không? Hay bạn thực sự chỉ mong đợi tên?

+1

Có thực sự đáng tiếc là 'Enum.Parse' chấp nhận biểu diễn chuỗi của một số không?Tôi sẽ xem xét nó bị hỏng nếu nó không, bởi vì nó sẽ có nghĩa là một giá trị enum có thể không vòng chuyến đi đến và đi từ một chuỗi, tức là 'Enum.Parse (enumValue.ToString())' có thể thất bại. –

3

Một enum có thể là bất kỳ giá trị nào của loại số nguyên cơ bản. Nó không chỉ giới hạn trong các hằng số được đặt tên.

Ví dụ, sau đây là hoàn toàn hợp lệ:

enum Foo{ 
    A, 
    B, 
    C, 
    D 
} 

Foo x = (Foo)5; 

Mặc dù 5 không tương ứng với một hằng số được đặt tên, nó vẫn là một giá trị hợp lệ cho Foo, kể từ khi loại cơ bản cho FooInt32.

Nếu một người gọi x.ToString(), giá trị trả lại sẽ đơn giản là "5", vì không có hằng số được đặt tên nào tương ứng với giá trị của x.

Enum.Parse() là chức năng trò chuyện của Enum.ToString(). Bạn nên mong đợi rằng bất cứ điều gì Enum.ToString() có thể trả lại rằng Enum.Parse() có thể chấp nhận. Điều này bao gồm, ví dụ, các giá trị bằng dấu phẩy cho cờ enums:

[Flags] 
enum Foo{ 
    A = 1, 
    B = 2, 
    C = 4, 
    D = 8 
} 

Foo x = Foo.A | Foo.B | Foo.C | Foo.D; 
int i = (int)x; 
string s = x.ToString(); 
Console.WriteLine(i); 
Console.WriteLine(s); 
Console.WriteLine((Foo)Enum.Parse(typeof(Foo), i.ToString()) == x); 
Console.WriteLine((Foo)Enum.Parse(typeof(Foo), s) == x); 

Output:

 
15 
A, B, C, D 
True 
True 

EDIT:

gì bạn thực sự dường như muốn là một cái gì đó như thế này:

static Enum GetEnumValue(Type enumType, string name){ 
    // null-checking omitted for brevity 

    int index = Array.IndexOf(Enum.GetNames(enumType), name); 
    if(index < 0) 
     throw new ArgumentException("\"" + name + "\" is not a value in " + enumType, "name"); 

    return Enum.GetValues(enumType).GetValue(index); 
} 

hoặc phiên bản không phân biệt chữ hoa chữ thường:

static Enum GetEnumValue(Type enumType, string name, bool ignoreCase){ 
    // null-checking omitted 

    int index; 
    if(ignoreCase) 
     index = Array.FindIndex(Enum.GetNames(enumType), 
      s => string.Compare(s, name, StringComparison.OrdinalIgnoreCase) == 0); 
      // or StringComparison.CurrentCultureIgnoreCase or something if you 
      // need to support fancy Unicode names 
    else index = Array.IndexOf(Enum.GetNames(enumType), name); 

    if(index < 0) 
     throw new ArgumentException("\"" + name + "\" is not a value in " + enumType, "name"); 

    return Enum.GetValues(enumType).GetValue(index); 
} 
+0

Cảm ơn bạn đã tìm hiểu thêm về 'Enum.Parse()' và 'ToString()', tôi không biết về đối tượng địa lý có các giá trị được phân tách bằng dấu phẩy. – Markus

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