2010-04-16 37 views
279

thể trùng lặp:
Getting attributes of Enum’s valueLàm thế nào để có được mô tả C# Enum từ giá trị?

Tôi có một enum với Mô tả các thuộc tính như thế này:

public enum MyEnum 
{ 
    Name1 = 1, 
    [Description("Here is another")] 
    HereIsAnother = 2, 
    [Description("Last one")] 
    LastOne = 3 
} 

tôi thấy chút mã này để lấy mô tả dựa trên một Enum

public static string GetEnumDescription(Enum value) 
{ 
    FieldInfo fi = value.GetType().GetField(value.ToString()); 

    DescriptionAttribute[] attributes = 
     (DescriptionAttribute[])fi.GetCustomAttributes(
     typeof(DescriptionAttribute), 
     false); 

    if (attributes != null && 
     attributes.Length > 0) 
     return attributes[0].Description; 
    else 
     return value.ToString(); 
} 

này cho phép tôi để viết mã như:

var myEnumDescriptions = from MyEnum n in Enum.GetValues(typeof(MyEnum)) 
         select new { ID = (int)n, Name = Enumerations.GetEnumDescription(n) }; 

Những gì tôi muốn làm là nếu tôi biết giá trị enum (ví dụ 1) - làm cách nào tôi có thể truy xuất mô tả? Nói cách khác, làm cách nào tôi có thể chuyển đổi một số nguyên thành "Giá trị enum" để chuyển sang phương thức GetDescription của tôi?

+0

(! Thuộc tính = null) sẽ luôn luôn được đúng và khác là thừa. – Jeff

+1

không gian tên cần thiết cho Mô tả là System.ComponentModel –

Trả lời

277
int value = 1; 
string description = Enumerations.GetEnumDescription((MyEnum)value); 

Giá trị mặc định cơ bản kiểu dữ liệu cho một enum trong C# là một int, bạn chỉ có thể cast nó.

+2

hoàn hảo. Chính xác những gì tôi muốn. Tôi biết nó sẽ đơn giản! Bây giờ, nếu stackoverflow sẽ chỉ cho phép tôi chấp nhận câu trả lời này ... nó nói rằng tôi cần phải chờ đợi 7 phút. – davekaro

+41

Tại sao tôi không tìm thấy bất kỳ lớp Enumerations nào trong khung .Net? –

+53

Lớp Enumerations là một cái gì đó mà người hỏi câu hỏi đã tự viết, và hàm GetEnumDescription() có trong câu hỏi. –

5

Bạn không thể dễ dàng làm điều này một cách chung chung: bạn chỉ có thể chuyển đổi một số nguyên thành một kiểu cụ thể của enum. Như Nicholas đã chỉ ra, đây là một diễn viên tầm thường nếu bạn chỉ quan tâm đến một loại enum, nhưng nếu bạn muốn viết một phương pháp chung có thể xử lý các loại enums khác nhau, mọi thứ trở nên phức tạp hơn một chút. Bạn muốn có một phương pháp dọc theo dòng:

public static string GetEnumDescription<TEnum>(int value) 
{ 
    return GetEnumDescription((Enum)((TEnum)value)); // error! 
} 

nhưng kết quả này trong một lỗi biên dịch rằng "int không thể được chuyển đổi sang TEnum" (và nếu bạn làm việc xung quanh này, rằng "TEnum không thể được chuyển đổi để Enum ").Vì vậy, bạn cần phải đánh lừa trình biên dịch bằng cách chèn phôi phản đối:

public static string GetEnumDescription<TEnum>(int value) 
{ 
    return GetEnumDescription((Enum)(object)((TEnum)(object)value)); // ugly, but works 
} 

Bây giờ bạn có thể gọi đây là để có được một mô tả cho bất cứ loại enum là trong tầm tay:

GetEnumDescription<MyEnum>(1); 
GetEnumDescription<YourEnum>(2); 
+0

Làm thế nào là "GetEnumDescription (1);" tốt hơn GetEnumDescription ((MyEnum) 1); ? – davekaro

+0

@davekaro: Thực hiện như thế này, nó không tốt hơn nhiều, nhưng việc triển khai mạnh mẽ hơn dựa trên generics có thể làm được điều này mà không có diễn viên rõ ràng, vì vậy bạn không mạo hiểm ngoại lệ nếu số đó không thực sự khớp với bất kỳ giá trị enum. – Aaronaught

+0

Thú vị. Chỉ cần làm rõ cho người đọc trong tương lai: Một người sẽ không nhận được một ngoại lệ chưa được giải quyết trên một diễn viên rõ ràng nếu số không khớp với một trong các giá trị enum (bạn có thể nói "MyEnum value = (MyEnum) 5;" và dòng đó sẽ thực thi tốt, nhưng bạn sẽ đánh bom trong dòng đầu tiên của GetEnumDescription() như được thực hiện trong câu hỏi gốc (vì GetField() sẽ trả về null vì nó không thể tìm thấy trường phù hợp với giá trị đó). d cần phải kiểm tra Enum.IsDefined() đầu tiên và trả về null hoặc một chuỗi rỗng, hoặc chỉ cần ném một ArgumentOutOfRangeException mình.) –

68

tôi thực hiện điều này trong một chung chung, kiểu an cách Unconstrained Melody - bạn muốn sử dụng:

string description = Enums.GetDescription((MyEnum)value); 

này:

  • Đảm bảo (với các ràng buộc kiểu chung chung) mà giá trị thực sự là một giá trị enum
  • Tránh boxing trong dung dịch hiện tại của bạn
  • Caches tất cả các mô tả để tránh sử dụng phản ánh trên mỗi cuộc gọi
  • Có một loạt các khác phương pháp, bao gồm khả năng để phân tích giá trị từ mô tả

tôi nhận ra câu trả lời chính là chỉ các diễn viên từ một int để MyEnum, nhưng nếu bạn đang làm rất nhiều enum làm việc nó có giá trị suy nghĩ về việc sử dụng Unconstrained Melody :)

+0

Không phải là "giá trị" một int? Vì vậy, không Enums.GetDescription ((MyEnum) giá trị) chỉ cần cast int vào MyEnum? – davekaro

+0

@davekaro: Nó gán int vào MyEnum - nhưng bạn sẽ không thể gọi nó với bất kỳ không enum, bao gồm một tham chiếu "Enum". Về cơ bản nó giống như mã của bạn, nhưng với một số –

+1

@JonSkeet Tôi không thấy phương pháp này trong Enum s.cs trong https://code.google.com/p/unconstrained-melody/downloads/detail?name=UnconstrainedMelody-0.0.0.2-src.zip&can=2&q= – tom

19

Để làm điều này dễ dàng hơn để sử dụng, tôi đã viết một phần mở rộng generic:

public static string ToDescription<TEnum>(this TEnum EnumValue) where TEnum : struct 
{ 
    return Enumerations.GetEnumDescription((Enum)(object)((TEnum)EnumValue)); 
} 

bây giờ tôi có thể viết:

 MyEnum my = MyEnum.HereIsAnother; 
     string description = my.ToDescription(); 
     System.Diagnostics.Debug.Print(description); 

Lưu ý: thay thế "Enumerations" ở trên với tên lớp của bạn

50

Tôi đặt mã với nhau từ câu trả lời được chấp nhận trong một phương pháp mở rộng chung, vì vậy nó có thể được sử dụng cho tất cả các loại đối tượng:

public static string DescriptionAttr<T>(this T source) 
{ 
    FieldInfo fi = source.GetType().GetField(source.ToString()); 

    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
     typeof(DescriptionAttribute), false); 

    if (attributes != null && attributes.Length > 0) return attributes[0].Description; 
    else return source.ToString(); 
} 

Sử dụng một enum như trong các bài bản gốc, hoặc bất kỳ lớp khác có sở hữu được trang trí với mô tả thuộc tính, các mã có thể được tiêu thụ như thế này:

string enumDesc = MyEnum.HereIsAnother.DescriptionAttr(); 
string classDesc = myInstance.SomeProperty.DescriptionAttr(); 
+2

chuỗi classDesc = myInstance.SomeProperty.DescriptionAttr(); Rằng sẽ không làm việc! Giả sử bạn có lớp Test {public int TestInt {get; bộ;} }. Vì vậy, nếu bạn sẽ gọi test mới() TestInt.DescriptionAttr(), bạn sẽ nhận được ngoại lệ tham chiếu null - 0.GetType(). GetField ("0") – Vladimirs

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