2009-09-15 39 views
16

Tôi có một kiểu enum như thế này là một ví dụ:Parse chuỗi enum loại

public Enum MyEnum { 
    enum1, enum2, enum3 }; 

Tôi sẽ đọc một chuỗi từ tập tin cấu hình. Những gì tôi cần nó để phân tích chuỗi để MyEnum loại hoặc null o không được xác định. Không chắc chắn nếu các mã sau đây sẽ làm việc (xin lỗi vì không có quyền truy cập vào VS của tôi ngay bây giờ):

// example: ParseEnum<MyEnum>("ENUM1", ref eVal); 
bool ParseEnum<T>(string value1, ref eVal) where T : Enum 
{ 
    bool bRet = false; 
    var x = from x in Enum.GetNames(typeof(T)) where 
     string.Equals(value1, x, StringComparison. OrdinalIgnoreCase) 
     select x; 
    if (x.Count() == 1) 
    { 
    eVal = Enum.Parse(typeof(T), x.Item(0)) as T; 
    bRet = true; 
    } 
    return bRet; 
} 

không chắc chắn nếu nó là đúng hoặc có bất kỳ cách đơn giản khác để phân tích một chuỗi giá trị MyEnum?

+0

Check-out Enum.TryParse, như đã đề cập trong [bài này] (http://www.codeducky.org/ins- outs-c-enums /). – ChaseMedallion

Trả lời

31

gì về cái gì đó như:

public static class EnumUtils 
{ 
    public static Nullable<T> Parse<T>(string input) where T : struct 
    { 
     //since we cant do a generic type constraint 
     if (!typeof(T).IsEnum) 
     { 
      throw new ArgumentException("Generic Type 'T' must be an Enum"); 
     } 
     if (!string.IsNullOrEmpty(input)) 
     { 
      if (Enum.GetNames(typeof(T)).Any(
        e => e.Trim().ToUpperInvariant() == input.Trim().ToUpperInvariant())) 
      { 
       return (T)Enum.Parse(typeof(T), input, true); 
      } 
     } 
     return null; 
    } 
} 

Được sử dụng như:

MyEnum? value = EnumUtils.Parse<MyEnum>("foo"); 

(Lưu ý: phiên bản cũ sử dụng try/catch xung quanh Enum.Parse)

+1

Không nên sử dụng xử lý ngoại lệ trong luồng chương trình thông thường ... –

+1

@ Tôi biết, nhưng chắc chắn là dễ dàng trong các trường hợp như thế này :) –

+0

@Mark thực hiện một điểm tốt - thử/nắm bắt hiếm khi tốt ý kiến. Phiên bản đã chỉnh sửa hiệu quả hơn đáng kể so với phiên bản trong câu hỏi, vì nó chỉ thực hiện một phần liệt kê thay vì lên đến 3-ish. –

5
private enum MyEnum 
{ 
    Enum1 = 1, Enum2 = 2, Enum3 = 3, Enum4 = 4, Enum5 = 5, Enum6 = 6, 
    Enum7 = 7, Enum8 = 8, Enum9 = 9, Enum10 = 10 
} 

private static Object ParseEnum<T>(string s) 
{ 
    try 
    { 
     var o = Enum.Parse(typeof (T), s); 
     return (T)o; 
    } 
    catch(ArgumentException) 
    { 
     return null; 
    } 
} 

static void Main(string[] args) 
{ 
    Console.WriteLine(ParseEnum<MyEnum>("Enum11")); 
    Console.WriteLine(ParseEnum<MyEnum>("Enum1")); 
    Console.WriteLine(ParseEnum<MyEnum>("Enum6").GetType()); 
    Console.WriteLine(ParseEnum<MyEnum>("Enum10")); 
} 

OUTPUT:

//This line is empty as Enum11 is not there and function returns a null 
Enum1 
TestApp.Program+MyEnum 
Enum10 
Press any key to continue . . . 
2

Nếu bạn đang sử dụng .NET 3.5 (hoặc thậm chí 2.0, nếu bạn cắt bỏ các phương pháp khuyến nông), tôi đã có may mắn lớn với các kỹ thuật trong bài viết này:

Enumerations và Strings - Dừng Madness !

EDIT: Miền đã biến mất và hiện là trang trại liên kết. Tôi kéo mã (chút thay đổi và bổ sung vào theo thời gian) từ codebase của chúng tôi tại nơi làm việc, mà bây giờ bạn có thể tìm thấy ở đây:

https://gist.github.com/1305566

+2

Tham chiếu hiện trỏ đến một trang trại liên kết. Ban đầu tôi đã điều chỉnh bạn, nhưng bạn khá cao, vì vậy tôi đoán bạn không cố ý làm điều này, và bạn không nên bị phạt vì những gì xảy ra với nội dung ngoài tầm kiểm soát của bạn. Tôi đã tự mình tìm kiếm bài viết nhưng không biến bất cứ điều gì hiển nhiên. Bạn có thể xem liệu có liên kết tốt hơn cho nội dung này không? –

+0

@MichaelBlackburn: Có vẻ như anh chàng có tên miền đã biến mất. Tôi sẽ kiểm tra trong codebase của chúng tôi vào thứ hai và xem nếu tôi có thể tìm thấy những gì tôi mượn từ bài báo. –

2

Tôi có một phương pháp TryParseName trong UnconstrainedMelody, thư viện cho đại biểu và enum tiện ích các phương thức sử dụng các ràng buộc "không thể giải thích" thông qua một số thủ thuật postbuild. (Mã số sử dụng thư viện không cần một postbuild, chỉ để được rõ ràng.)

Bạn sẽ sử dụng nó như thế này:

Foo foo; 
bool parsed = Enums.TryParseName<Foo>(name, out foo); 

tôi hiện không có một phiên bản case-insensitive, nhưng tôi có thể dễ dàng giới thiệu nếu bạn muốn. Lưu ý rằng điều này không cố gắng phân tích cú pháp các số, ví dụ: "12" giống như phiên bản được tích hợp sẵn, cũng không cố phân tích cú pháp danh sách cờ được phân cách bằng dấu phẩy. Tôi có thể thêm các phiên bản cờ sau này, nhưng tôi không thể nhìn thấy nhiều điểm trong phiên bản số.

Việc này được thực hiện mà không cần quyền anh và không cần kiểm tra loại thời gian thực hiện. Có khó khăn thực sự tiện dụng :)

Xin vui lòng cho tôi biết nếu bạn muốn tìm một phân tích case-insensitive hữu ích ...

+0

@Jon Skeet, bạn có thể giới thiệu phương pháp quá tải bổ sung để cho phép người dùng có lựa chọn phân biệt chữ hoa chữ thường hay không. –

+0

@Joh Skeet, không chắc chắn nếu phương pháp của bạn nên (tên, ref foo) hay không. Nếu tryparse thất bại, bạn nên làm gì? Giá trị enum đầu tiên? Tôi nghĩ tốt hơn là cho phép người dùng khởi tạo nó và không thay đổi nó nếu không thành công. Tôi hiểu bạn cố gắng làm cho phương pháp này phù hợp với TryParse (tên, giá trị ngoài). –

+1

Nếu 'TryParse' không thành công, nó sẽ là' mặc định (Foo) 'phù hợp với' TryParse', 'TryGetValue' vv. Nếu tôi không đồng ý, tôi có thể trả về' Nullable 'thay thế. Tôi sẽ xem xét giới thiệu một tình trạng quá tải mới cho phù hợp với trường hợp không nhạy cảm - hoặc có thể lấy một StringComparer (hoặc tương tự) để cho phép độ nhạy văn hóa được chọn quá. –

1

Tôi vừa kết hợp các cú pháp từ here, với xử lý từ here ngoại lệ, để tạo điều này:

public static class Enum<T> 
{ 
    public static T Parse(string value) 
    { 
     //Null check 
     if(value == null) throw new ArgumentNullException("value"); 
     //Empty string check 
     value = value.Trim(); 
     if(value.Length == 0) throw new ArgumentException("Must specify valid information for parsing in the string", "value"); 
     //Not enum check 
     Type t = typeof(T); 
     if(!t.IsEnum) throw new ArgumentException("Type provided must be an Enum", "TEnum"); 

     return (T)Enum.Parse(typeof(T), value); 
    } 
} 

Bạn có thể xoắn một chút để trả về thay vì ném ngoại lệ.

+0

@Benjol, tôi thích kiểu sử dụng của bạn.IsEnum để kiểm tra loại của nó. –

1

Bạn có thể sử dụng TryParse nếu bạn muốn tránh sử dụng try/catch.

MyEnum eVal; 
if (Enum.TryParse("ENUM2", true, out eVal)){ 
    // now eVal is the enumeration element: enum2 
} 
//unable to parse. You can log the error, exit, redirect, etc... 

Tôi đã sửa đổi câu trả lời đã chọn một chút. Tôi hy vọng bạn thích nó.

public static class EnumUtils 
{ 
    public static Nullable<T> Parse<T>(string input) where T : struct 
    { 
     //since we cant do a generic type constraint 
     if (!typeof(T).IsEnum) 
     { 
      throw new ArgumentException("Generic Type 'T' must be an Enum"); 
     } 

     int intVal; 
     if (!string.IsNullOrEmpty(input) && !int.TryParse(input, out intVal)) 
     { 
      T eVal; 
      if (Enum.TryParse(input, true, out eVal)) 
      { 
       return eVal; 
      } 
     } 
     return null; 
    } 
} 
0

Để trở Enum bởi chuỗi, nếu chứa:

public static T GetEnum<T>(string s) 
    { 
     Array arr = Enum.GetValues(typeof(T)); 
     foreach (var x in arr) 
     { 
      if (x.ToString().Contains(s)) 
       return (T)x; 
     } 
     return default(T); 
    }