Enum ToString với chuỗi thân thiện với người dùng


282

Enum của tôi bao gồm các giá trị sau:

private enum PublishStatusses{
    NotCompleted,
    Completed,
    Error
};

Tôi muốn có thể xuất các giá trị này theo cách thân thiện với người dùng.
Tôi không cần phải có thể đi từ chuỗi này sang giá trị nữa.


bản sao có thể của enums Chuỗi C #
nawfal

Bản sao có thể có của đại diện Chuỗi của Enum
Liam

Câu trả lời:


350

Tôi sử dụng Descriptionthuộc tính từ không gian tên System.ComponentModel. Đơn giản chỉ cần trang trí enum:

private enum PublishStatusValue
{
    [Description("Not Completed")]
    NotCompleted,
    Completed,
    Error
};

Sau đó sử dụng mã này để lấy nó:

public static string GetDescription<T>(this T enumerationValue)
    where T : struct
{
    Type type = enumerationValue.GetType();
    if (!type.IsEnum)
    {
        throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
    }

    //Tries to find a DescriptionAttribute for a potential friendly name
    //for the enum
    MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
    if (memberInfo != null && memberInfo.Length > 0)
    {
        object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

        if (attrs != null && attrs.Length > 0)
        {
            //Pull out the description value
            return ((DescriptionAttribute)attrs[0]).Description;
        }
    }
    //If we have no description attribute, just return the ToString of the enum
    return enumerationValue.ToString();
}

12
Ví dụ này dễ đọc hơn. stackoverflow.com/questions/1415140/
Mạnh

31
Tôi nghi ngờ có một hiệu suất đáng kể để sử dụng sự phản chiếu như được mô tả trong giải pháp này. Mã cho phương pháp sử dụng phương thức mở rộng ToFriendlyString của Will dễ hiểu hơn nhiều và hiệu suất của nó cũng cực kỳ nhanh.
humbads

1
Tôi thích phiên bản mà @RayL liên kết vì nó sẽ chỉ thêm phương thức mở rộng vào Enums. Nếu đó là tất cả những gì bạn muốn sử dụng cho mục đích này (như được chỉ ra với ArgumentException, thì không có lý do gì để phương thức này hoàn toàn chung chung.
krillgar

4
Điều đó có nghĩa là mọi enum đều cần phương thức mở rộng của riêng nó. Đây là cách sử dụng chung hơn và đòi hỏi nhiều công việc hơn, nhưng có lẽ bạn muốn định lượng "nhanh" nghĩa là gì trước khi chúng tôi quyết định hiệu suất.
Ray Booysen

2
@petar hoạt động nhưng không phải nếu bạn muốn các chuỗi thân thiện được hiển thị cho người dùng. MY_TYPE sẽ có dấu gạch dưới và không thể tùy chỉnh.
Ray Booysen

354

Tôi làm điều này với các phương thức mở rộng:

public enum ErrorLevel
{
  None,
  Low,
  High,
  SoylentGreen
}

public static class ErrorLevelExtensions
{
  public static string ToFriendlyString(this ErrorLevel me)
  {
    switch(me)
    {
      case ErrorLevel.None:
        return "Everything is OK";
      case ErrorLevel.Low:
        return "SNAFU, if you know what I mean.";
      case ErrorLevel.High:
        return "Reaching TARFU levels";
      case ErrorLevel.SoylentGreen:
        return "ITS PEOPLE!!!!";
      default:
        return "Get your damn dirty hands off me you FILTHY APE!";
    }
  }
}

6
Điều này là rất nhiều hơn so với câu trả lời thuộc tính. Đẹp!
pennyrave

3
@pennyrave: Ơ. Rất nhiều thành phần UI đang mong đợi để tìm và sử dụng DisplayNameAttribution và descriptionAttribution. Trên thực tế, bây giờ, tôi sử dụng chúng và một phương thức mở rộng để dễ dàng lấy các giá trị đó ra.

60
Vấn đề tôi thấy với điều này là bạn liên tục viết các phương thức mở rộng này. Với cơ chế thuộc tính, đó là một cách trang trí đơn giản và chỉ gọi một phương thức.
Ray Booysen

5
Không chắc chắn những gì bạn có ý nghĩa?
Ray Booysen

9
Theo tôi, tốt hơn là cho phép defaultthực hiện trường hợp trả về me.ToString()và chỉ cung cấp các câu lệnh tình huống chuyển đổi cho các giá trị enum mà bạn muốn ghi đè. Trong ví dụ của bạn, tôi nhận thấy rằng tất cả chúng đều khác nhau nhưng trong các trường hợp sử dụng thực tế, tôi nghi ngờ rằng hầu hết các giá trị enum một từ sẽ đủ và bạn sẽ chỉ cung cấp ghi đè cho các giá trị enum nhiều từ.
Scott

78

Có lẽ tôi đang thiếu một cái gì đó, nhưng có gì sai với Enum.GetName?

public string GetName(PublishStatusses value)
{
    return Enum.GetName(typeof(PublishStatusses), value)
}

chỉnh sửa: đối với các chuỗi thân thiện với người dùng, bạn cần phải đi qua .resource để thực hiện quốc tế hóa / bản địa hóa và tốt hơn hết là sử dụng khóa cố định dựa trên khóa enum so với thuộc tính trang trí trên cùng.


11
Tôi trả về giá trị theo nghĩa đen của enum, không phải người dùng thân thiện.
Boris Callens

2
oic - vâng, có một trường hợp khá lớn mà bạn phải thông qua một thư viện tài nguyên chuỗi dựa trên giá trị này, bởi vì giải pháp thay thế (attribs trang trí) sẽ không hỗ trợ I18N
annakata

1
Trong trường hợp I18N, tôi sẽ thực hiện tìm kiếm phương thức GetDescrip () trong lib tài nguyên cho một chuỗi được dịch và quay lại mô tả và sau đó quay lại nghĩa đen.
Boris Callens

3
+1 cho MyEnum.ToString () làm khóa tài nguyên để bản địa hóa. Tôi đã làm điều đó trong nhiều năm
jackvsworld

1
@annakata chúng tôi thực sự đã mở rộng cơ chế thuộc tính để bao gồm hỗ trợ cho l18N, thực tế đó là một thay đổi đơn giản.
Ray Booysen

23

Tôi đã tạo một phương thức mở rộng ngược để chuyển đổi mô tả trở lại giá trị enum:

public static T ToEnumValue<T>(this string enumerationDescription) where T : struct
{
    var type = typeof(T);

    if (!type.IsEnum)
        throw new ArgumentException("ToEnumValue<T>(): Must be of enum type", "T");

    foreach (object val in System.Enum.GetValues(type))
        if (val.GetDescription<T>() == enumerationDescription)
            return (T)val;

    throw new ArgumentException("ToEnumValue<T>(): Invalid description for enum " + type.Name, "enumerationDescription");
}

15
Tôi xin lỗi, nhưng cảm ơn vì đã cố gắng giúp đỡ! Mặc dù vì đây là trang web Hỏi & Đáp, câu trả lời nên là một nỗ lực để trả lời trực tiếp câu hỏi. Và câu hỏi đặc biệt nêu rõ " Tôi không cần phải đi từ chuỗi này sang giá trị nữa. " Một lần nữa, cảm ơn!
Jesse

8
Cảm ơn những lời chỉ trích tích cực. Luôn luôn khó khăn khi mới đến một trang web và tìm hiểu về văn hóa và sắc thái của nó. Tôi rất vui vì có những người như bạn đã đặt những người mới. Một lần nữa, cảm ơn vì đã không từ bỏ anh chàng mới.
Brian Richardson

6
@Jlie Và 4 năm sau ai đó rất vui khi tìm thấy mã bjrichardson ở đây! SO có thể là một trang web Hỏi & Đáp, nhưng điều đó không có nghĩa là các câu hỏi đã chết sau khi được trả lời.
Giăng

18

Giải pháp đơn giản nhất ở đây là sử dụng một phương thức mở rộng tùy chỉnh (ít nhất là trong .NET 3.5 - bạn chỉ có thể chuyển đổi nó thành phương thức trợ giúp tĩnh cho các phiên bản khung trước đó).

public static string ToCustomString(this PublishStatusses value)
{
    switch(value)
    {
        // Return string depending on value.
    }
    return null;
}

Tôi giả sử ở đây rằng bạn muốn trả về một cái gì đó ngoài tên thực của giá trị enum (mà bạn có thể nhận được bằng cách gọi ToString).


Mặc dù hợp lệ, tôi thích cách thuộc tính hơn. Bằng cách đó, tôi có thể đặt phương thức toSTring của mình trong một thư viện riêng biệt, trong khi đặt biểu diễn chuỗi tùy chỉnh với chính enum
Boris Callens

1
Đủ công bằng. Tôi giả sử một ưu điểm của phương thức này là bạn có thể bao gồm một đối số với phương thức chỉ định một số biến trạng thái, và sau đó thay đổi biểu diễn chuỗi nào được trả về tùy thuộc vào điều này.
Noldorin

1
Vâng, tất cả phụ thuộc vào phạm vi của phương pháp tôi đoán. Mặc dù cách Thuộc tính chung chung hơn, nhưng giải pháp của bạn lại mang tính địa phương hơn .. Cuối cùng tất cả là về nhu cầu.
Boris Callens

1
Bạn có thể đặt các phương thức mở rộng bất cứ nơi nào bạn muốn. Bạn chỉ cần tham khảo nó ở nơi bạn muốn sử dụng chúng.

Có, nhưng điều này có nghĩa là phương pháp mở rộng này nên được viết lại mỗi khi bạn giới thiệu một enum mới mà bạn muốn có một cái tên thân thiện. Điều này cũng có nghĩa là TẤT CẢ các ứng dụng của bạn sẽ mang theo những cái tên thân thiện cho TẤT CẢ các ứng dụng khác của bạn ...
Boris Callens

13

Bài đăng khác là Java. Bạn không thể đặt các phương thức trong Enums trong C #.

chỉ cần làm một cái gì đó như thế này:

PublishStatusses status = ...
String s = status.ToString();

Nếu bạn muốn sử dụng các giá trị hiển thị khác nhau cho các giá trị enum của mình, bạn có thể sử dụng Thuộc tính và Phản xạ.


3
toString không an toàn trong mọi trường hợp - một enum có nhiều mục có cùng giá trị (giả sử là enum số nguyên) sẽ trả về khóa của giá trị khớp đầu tiên, không phải là khóa của mục được kiểm tra, đây là lý do Enum.GetName được ưa thích
annakata

4
Chà, đó là giải pháp dễ nhất cho enum cụ thể của anh ấy
Lemmy

9

Cách đơn giản nhất là đưa lớp mở rộng này vào dự án của bạn, nó sẽ hoạt động với bất kỳ enum nào trong dự án:

public static class EnumExtensions
{
    public static string ToFriendlyString(this Enum code)
    {
        return Enum.GetName(code.GetType(), code);
    }
}

Sử dụng:

enum ExampleEnum
{
    Demo = 0,
    Test = 1, 
    Live = 2
}

...

ExampleEnum ee = ExampleEnum.Live;
Console.WriteLine(ee.ToFriendlyString());

2
Đó là một bí ẩn về lý do tại sao bình luận này không được chấp nhận hoặc được đánh giá cao nhất - không có sự phản ánh, không có thuộc tính không cần thiết, lý tưởng cho các tình huống đơn giản trong đó enum đã được đặt tên độc đáo. Bạn có thể đưa câu trả lời này thêm một bước nữa và cho phép thêm khoảng trắng ở giữa chữ in hoa trước khi quay lại, 'Enum của tôi'.
Vix

12
Nếu enum đã được đặt tên độc đáo, không cần bất kỳ phương thức mở rộng nào. Chỉ cần sử dụng phương thức ToString () hiện có. string result = "Result: " + ee;
Giăng

Đây phải là câu trả lời tốt nhất. Nó hoạt động cho bất kỳ enum. Bạn thậm chí có thể triển khai nó bằng cách sử dụng Enum cụ thể chỉ bằng cách thay đổi loại Enum của tham số thành Enum thực tế để sử dụng nó.
Juanu Haedo

6
Câu trả lời này và tất cả các ý kiến ​​bỏ qua yêu cầu ban đầu cho một mô tả mở rộng. Các bạn hoàn toàn bỏ lỡ bài tập trả về thứ gì đó ngoài giá trị ToString mặc định. Tôi sẽ không tải xuống tất cả các ghi chú cho câu trả lời này ở đây nhưng tôi chắc chắn muốn.
TonyG

8

Một số tùy chọn nguyên thủy khác tránh các lớp / kiểu tham chiếu:

  • Phương thức mảng
  • Phương pháp cấu trúc lồng nhau

Phương thức mảng

private struct PublishStatusses
{
    public static string[] Desc = {
        "Not Completed",
        "Completed",
        "Error"
    };

    public enum Id
    {
        NotCompleted = 0,
        Completed,
        Error
    };
}

Sử dụng

string desc = PublishStatusses.Desc[(int)PublishStatusses.Id.Completed];

Phương pháp cấu trúc lồng nhau

private struct PublishStatusses
{
    public struct NotCompleted
    {
        public const int Id = 0;
        public const string Desc = "Not Completed";
    }

    public struct Completed
    {
        public const int Id = 1;
        public const string Desc = "Completed";
    }

    public struct Error
    {
        public const int Id = 2;
        public const string Desc = "Error";
    }            
}

Sử dụng

int id = PublishStatusses.NotCompleted.Id;
string desc = PublishStatusses.NotCompleted.Desc;

Cập nhật (03/09/2018)

Một sự kết hợp của Phương pháp mở rộng và kỹ thuật đầu tiên ở trên.

Tôi thích enum được xác định nơi chúng "thuộc về" (gần nhất với nguồn gốc của chúng chứ không phải trong một số không gian tên chung, chung).

namespace ViewModels
{
    public class RecordVM
    {
        //public enum Enum { Minutes, Hours }
        public struct Enum
        {
            public enum Id { Minutes, Hours }
            public static string[] Name = { "Minute(s)", "Hour(s)" };
        }
    }
}

Phương thức mở rộng có vẻ phù hợp với một khu vực chung và định nghĩa "cục bộ hóa" của enum hiện làm cho phương thức mở rộng dài dòng hơn.

namespace Common
{
    public static class EnumExtensions
    {
        public static string Name(this RecordVM.Enum.Id id)
        {
            return RecordVM.Enum.Name[(int)id];
        }
    }   
}

Một ví dụ sử dụng của enum và phương thức mở rộng của nó.

namespace Views
{
    public class RecordView 
    {
        private RecordDataFieldList<string, string> _fieldUnit;

        public RecordView()
        {
            _fieldUnit.List = new IdValueList<string, string>
            {            
                new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
                new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
            };
        }

        private void Update()
        {    
            RecordVM.Enum.Id eId = DetermineUnit();

            _fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
        }
    }
}

Lưu ý: Tôi thực sự đã quyết định loại bỏ Enumtrình bao bọc (và Namemảng), vì tốt nhất là các chuỗi tên đến từ một tài nguyên (ví dụ: tệp cấu hình hoặc DB) thay vì được mã hóa cứng và vì cuối cùng tôi đã đưa phương thức mở rộng vào ViewModelskhông gian tên (chỉ trong một tệp "CommonVM.cs" khác). Cộng với toàn bộ .Idđiều trở nên mất tập trung và cồng kềnh.

namespace ViewModels
{
    public class RecordVM
    {
        public enum Enum { Minutes, Hours }
        //public struct Enum
        //{
        //    public enum Id { Minutes, Hours }
        //    public static string[] Name = { "Minute(s)", "Hour(s)" };
        //}
    }
}

CommonVM.cs

//namespace Common
namespace ViewModels
{
    public static class EnumExtensions
    {
        public static string Name(this RecordVM.Enum id)
        {
            //return RecordVM.Enum.Name[(int)id];
            switch (id)
            {
                case RecordVM.Enum.Minutes: return "Minute(s)";                    
                case RecordVM.Enum.Hours: return "Hour(s)";
                default: return null;
            }
        }
    }   
}

Một ví dụ sử dụng của enum và phương thức mở rộng của nó.

namespace Views
{
    public class RecordView 
    {
        private RecordDataFieldList<string, string> _fieldUnit

        public RecordView()
        {
            _fieldUnit.List = new IdValueList<string, string>
            {            
                new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
                new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
            };
        }

        private void Update()
        {    
            RecordVM.Enum eId = DetermineUnit();

            _fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
        }
    }
}

+ 1-1 = 0 phiếu: Giải pháp này bảo toàn cú pháp Enum và giải quyết vấn đề một cách tao nhã mà không cần phản ánh hoặc mã phức tạp, vì vậy +1 ở đó. Nhưng nó làm mất các tính năng của Enums. Vì vậy, trong khi IMO đây là một lựa chọn tốt, nó không trả lời câu hỏi thực tế và được -1. Net 0. Xin lỗi, chúng tôi không có cách nào ghi lại điều đó tốt hơn trong SO.
TonyG

@TonyG Đủ công bằng. Sau khi bỏ lỡ một vài câu hỏi trong đánh giá kỹ năng .net của pluarlsight.com, tôi bắt đầu nhận ra mức độ sâu của C # enum, vì vậy, có lẽ ít nhất nên biết về khả năng của họ trước khi quyết định áp dụng phương pháp nào (đặc biệt là sử dụng phương pháp phổ biến, tái cấu trúc có thể là một chút thời gian;).
samis

7

Bạn có thể sử dụng Humanizer gói với nhân đạo Enums possiblity. Một mẫu mã:

enum PublishStatusses
{
    [Description("Custom description")]
    NotCompleted,
    AlmostCompleted,
    Error
};

sau đó bạn có thể sử dụng Humanizephương thức mở rộng trên enum trực tiếp:

var st1 = PublishStatusses.NotCompleted;
var str1 = st1.Humanize(); // will result in Custom description

var st2 = PublishStatusses.AlmostCompleted;
var str2 = st2.Humanize(); // will result in Almost completed (calculated automaticaly)

Nó sử dụng sự phản chiếu là tốt và không được lưu trữ. github.com/Humanizr/Humanizer/blob/ từ
Konrad

Nó sẽ chậm như giải pháp trong câu trả lời đầu tiên của Ray
Konrad

5

Đối với Ray Booysen, có một lỗi trong mã: Enum ToString với chuỗi thân thiện với người dùng

Bạn cần tính đến nhiều thuộc tính trên các giá trị enum.

public static string GetDescription<T>(this object enumerationValue)
            where T : struct
    {
        Type type = enumerationValue.GetType();
        if (!type.IsEnum)
        {
            throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
        }

        //Tries to find a DescriptionAttribute for a potential friendly name
        //for the enum
        MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
        if (memberInfo != null && memberInfo.Length > 0)
        {
            object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
            {
                //Pull out the description value
                return ((DescriptionAttribute)attrs.Where(t=>t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description;
            }
        }
        //If we have no description attribute, just return the ToString of the enum
        return enumerationValue.ToString();

4
Việc bỏ qua kiểm tra cho nhiều thuộc tính Mô tả là có chủ đích. Nếu enum có hai và bạn đang sử dụng để tạo mô tả, tôi muốn nghĩ rằng đó là một trường hợp đặc biệt. Tôi nghĩ rằng lỗi thực tế là tôi không thực hiện Single () để ném ngoại lệ. Nếu không, toàn bộ chữ ký phương thức không có ý nghĩa. GetDes mô tả ()? Mô tả nào? Một tổng hợp?
Ray Booysen

4
public enum MyEnum
{
    [Description("Option One")]
    Option_One
}

public static string ToDescriptionString(this Enum This)
{
    Type type = This.GetType();

    string name = Enum.GetName(type, This);

    MemberInfo member = type.GetMembers()
        .Where(w => w.Name == name)
        .FirstOrDefault();

    DescriptionAttribute attribute = member != null
        ? member.GetCustomAttributes(true)
            .Where(w => w.GetType() == typeof(DescriptionAttribute))
            .FirstOrDefault() as DescriptionAttribute
        : null;

    return attribute != null ? attribute.Description : name;
}

3
Thật tuyệt khi viết một số văn bản giải thích lý do tại sao điều này nên hoạt động và tại sao OP không.
phaberest

Chỉ cần FYI, các quy ước mã C # muốn các biến cục bộ và tham số phương thức với chữ cái đầu tiên viết thường. Một ngoại lệ là thistham số trong các phương thức mở rộng, mà bạn có thể thấy được gọi Thistrong nhiều ví dụ trên web. Gọi nó giống như kiểu của bạn như bạn đã làm ( Enum Enum) làm cho mã ít đọc hơn.
Massimiliano Kraus

4

Thay vì sử dụng enum, hãy sử dụng lớp tĩnh.

thay thế

private enum PublishStatuses{
    NotCompleted,
    Completed,
    Error
};

với

private static class PublishStatuses{
    public static readonly string NotCompleted = "Not Completed";
    public static readonly string Completed = "Completed";
    public static readonly string Error = "Error";
};

nó sẽ được sử dụng như thế này

PublishStatuses.NotCompleted; // "Not Completed"

Vấn đề sử dụng các giải pháp "phương pháp mở rộng" hàng đầu:

Một enum riêng thường được sử dụng trong một lớp khác. Giải pháp phương thức mở rộng không hợp lệ ở đó vì nó phải nằm trong lớp riêng của nó. Giải pháp này có thể là riêng tư và được nhúng trong một lớp khác.


2

Tôi tình cờ là một người hâm mộ VB.NET, vì vậy đây là phiên bản của tôi, kết hợp phương thức Mô tả Mô tả với một phương thức mở rộng. Đầu tiên, kết quả:

Imports System.ComponentModel ' For <Description>

Module Module1
  ''' <summary>
  ''' An Enum type with three values and descriptions
  ''' </summary>
  Public Enum EnumType
    <Description("One")>
    V1 = 1

    ' This one has no description
    V2 = 2

    <Description("Three")>
    V3 = 3
  End Enum

  Sub Main()
    ' Description method is an extension in EnumExtensions
    For Each v As EnumType In [Enum].GetValues(GetType(EnumType))
      Console.WriteLine("Enum {0} has value {1} and description {2}",
        v,
        CInt(v),
        v.Description
      )
    Next
    ' Output:
    ' Enum V1 has value 1 and description One
    ' Enum V2 has value 2 and description V2
    ' Enum V3 has value 3 and description Three
  End Sub
End Module

Nội dung cơ bản: một enum được gọi là EnumType với ba giá trị V1, V2 và V3. "Phép thuật" xảy ra trong lệnh gọi Console.WriteLine trong Sub Main (), trong đó đối số cuối cùng chỉ đơn giản là v.Description. Điều này trả về "Một" cho V1, "V2" cho V2 và "Ba" cho V3. Phương thức Mô tả này trên thực tế là một phương thức mở rộng, được định nghĩa trong một mô-đun khác gọi là EnumExtensions:

Option Strict On
Option Explicit On
Option Infer Off

Imports System.Runtime.CompilerServices
Imports System.Reflection
Imports System.ComponentModel

Module EnumExtensions
  Private _Descriptions As New Dictionary(Of String, String)

  ''' <summary>
  ''' This extension method adds a Description method
  ''' to all enum members. The result of the method is the
  ''' value of the Description attribute if present, else
  ''' the normal ToString() representation of the enum value.
  ''' </summary>
  <Extension>
  Public Function Description(e As [Enum]) As String
    ' Get the type of the enum
    Dim enumType As Type = e.GetType()
    ' Get the name of the enum value
    Dim name As String = e.ToString()

    ' Construct a full name for this enum value
    Dim fullName As String = enumType.FullName + "." + name

    ' See if we have looked it up earlier
    Dim enumDescription As String = Nothing
    If _Descriptions.TryGetValue(fullName, enumDescription) Then
      ' Yes we have - return previous value
      Return enumDescription
    End If

    ' Find the value of the Description attribute on this enum value
    Dim members As MemberInfo() = enumType.GetMember(name)
    If members IsNot Nothing AndAlso members.Length > 0 Then
      Dim descriptions() As Object = members(0).GetCustomAttributes(GetType(DescriptionAttribute), False)
      If descriptions IsNot Nothing AndAlso descriptions.Length > 0 Then
        ' Set name to description found
        name = DirectCast(descriptions(0), DescriptionAttribute).Description
      End If
    End If

    ' Save the name in the dictionary:
    _Descriptions.Add(fullName, name)

    ' Return the name
    Return name
  End Function
End Module

Bởi vì việc tìm kiếm các thuộc tính mô tả sử dụng Reflectionrất chậm, việc tra cứu cũng được lưu trữ riêng tưDictionary , được điền theo yêu cầu.

.


2

Tóm tắt sạch các đề xuất trên với mẫu:

namespace EnumExtensions {

using System;
using System.Reflection;

public class TextAttribute : Attribute {
   public string Text;
   public TextAttribute( string text ) {
      Text = text;
   }//ctor
}// class TextAttribute

public static class EnumExtender {

public static string ToText( this Enum enumeration ) {

   MemberInfo[] memberInfo = enumeration.GetType().GetMember( enumeration.ToString() );

   if ( memberInfo != null && memberInfo.Length > 0 ) {

      object[] attributes = memberInfo[ 0 ].GetCustomAttributes( typeof(TextAttribute),  false );

      if ( attributes != null && attributes.Length > 0 ) {
         return ( (TextAttribute)attributes[ 0 ] ).Text;
      }

   }//if

   return enumeration.ToString();

}//ToText

}//class EnumExtender

}//namespace

SỬ DỤNG:

using System;
using EnumExtensions;

class Program {

public enum Appearance {

  [Text( "left-handed" ) ]
  Left,

  [Text( "right-handed" ) ]
  Right,

}//enum

static void Main( string[] args ) {

   var appearance = Appearance.Left;
   Console.WriteLine( appearance.ToText() );

}//Main

}//class

1
Có một thuộc tính [Mô tả ("")] trong C #, tại sao không sử dụng thuộc tính này?
Stefan Koenen

Tất nhiên sử dụng [Mô tả ("")] là một cách để đi. Nhưng tôi muốn mẫu được hoàn thành.
gạch dưới

2

Sử dụng Enum.GetName

Từ liên kết trên ...

using System;

public class GetNameTest {
    enum Colors { Red, Green, Blue, Yellow };
    enum Styles { Plaid, Striped, Tartan, Corduroy };

    public static void Main() {

        Console.WriteLine("The 4th value of the Colors Enum is {0}", Enum.GetName(typeof(Colors), 3));
        Console.WriteLine("The 4th value of the Styles Enum is {0}", Enum.GetName(typeof(Styles), 3));
    }
}
// The example displays the following output:
//       The 4th value of the Colors Enum is Yellow
//       The 4th value of the Styles Enum is Corduroy

2

Theo tài liệu này: https://docs.microsoft.com/pt-br/dotnet/api/system.enum.tostring?view=netframework-4.8

Có thể chỉ cần chuyển đổi một điều tra viên thành chuỗi bằng định dạng như thế này:

public enum Example
{
    Example1,
    Example2
}

Console.WriteLine(Example.Example1.ToString("g"));

//Outputs: "Example1"

Bạn có thể thấy tất cả các định dạng có thể có trong liên kết này: https://docs.microsoft.com/pt-br/dotnet/api/system.opes?view=netframework-4.8


1

Đây là bản cập nhật cho mã của Ray Booysen sử dụng phương thức GetCustomAttribut và LINQ chung để làm cho mọi thứ gọn gàng hơn một chút.

    /// <summary>
    /// Gets the value of the <see cref="T:System.ComponentModel.DescriptionAttribute"/> on an struct, including enums.  
    /// </summary>
    /// <typeparam name="T">The type of the struct.</typeparam>
    /// <param name="enumerationValue">A value of type <see cref="T:System.Enum"/></param>
    /// <returns>If the struct has a Description attribute, this method returns the description.  Otherwise it just calls ToString() on the struct.</returns>
    /// <remarks>Based on http://stackoverflow.com/questions/479410/enum-tostring/479417#479417, but useful for any struct.</remarks>
    public static string GetDescription<T>(this T enumerationValue) where T : struct
    {
        return enumerationValue.GetType().GetMember(enumerationValue.ToString())
                .SelectMany(mi => mi.GetCustomAttributes<DescriptionAttribute>(false),
                    (mi, ca) => ca.Description)
                .FirstOrDefault() ?? enumerationValue.ToString();
    }   

Không thấy lý do tại sao bạn cần nó là chung chung? Nếu bạn sẽ sử dụng sự phản chiếu?
Lee Louviere

@LeeLouviere Chủ yếu để tránh quyền anh khi cấu trúc (loại giá trị) được truyền dưới dạng tham số.
Richard Anthony Hein

1
thay vì numationValue.GetType () sử dụng: typeof (T).
Slava

1
Cải thiện lớn một dòng so với câu trả lời được chấp nhận mà không (YMMV) mất khả năng đọc. Có, với typeof (T).
TonyG

1

Tóm tắt thậm chí sạch hơn:

using System;
using System.Reflection;

public class TextAttribute : Attribute
{
    public string Text;
    public TextAttribute(string text)
    {
        Text = text;
    }
}  

public static class EnumExtender
{
    public static string ToText(this Enum enumeration)
    {
        var memberInfo = enumeration.GetType().GetMember(enumeration.ToString());
        if (memberInfo.Length <= 0) return enumeration.ToString();

        var attributes = memberInfo[0].GetCustomAttributes(typeof(TextAttribute), false);
        return attributes.Length > 0 ? ((TextAttribute)attributes[0]).Text : enumeration.ToString();
    }
}

Cách sử dụng tương tự như gạch dưới mô tả.


0

Đối với cờ enum bao gồm.

    public static string Description(this Enum value)
    {
        Type type = value.GetType();

        List<string> res = new List<string>();
        var arrValue = value.ToString().Split(',').Select(v=>v.Trim());
        foreach (string strValue in arrValue)
        {
            MemberInfo[] memberInfo = type.GetMember(strValue);
            if (memberInfo != null && memberInfo.Length > 0)
            {
                object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

                if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
                {
                    res.Add(((DescriptionAttribute)attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description);
                }
                else
                    res.Add(strValue);
            }
            else
                res.Add(strValue);
        }

        return res.Aggregate((s,v)=>s+", "+v);
    }

0

Trong trường hợp bạn chỉ muốn thêm khoảng trắng giữa các từ, nó đơn giản như

string res = Regex.Replace(PublishStatusses.NotCompleted, "[A-Z]", " $0").Trim();

0

Tôi sử dụng một lớp chung để lưu trữ các cặp enum / mô tả và một lớp trình trợ giúp lồng nhau để có được mô tả.

Các enum :

enum Status { Success, Fail, Pending }

Lớp chung:

Lưu ý: Vì một lớp chung không thể bị ràng buộc bởi một enum nên tôi bị ràng buộc bởi struct thay vào đó và kiểm tra enum trong hàm tạo.

public class EnumX<T> where T : struct
{
    public T Code { get; set; }
    public string Description { get; set; }

    public EnumX(T code, string desc)
    {
        if (!typeof(T).IsEnum) throw new NotImplementedException();

        Code = code;
        Description = desc;
    }

    public class Helper
    {
        private List<EnumX<T>> codes;

        public Helper(List<EnumX<T>> codes)
        {
            this.codes = codes;
        }

        public string GetDescription(T code)
        {
            EnumX<T> e = codes.Where(c => c.Code.Equals(code)).FirstOrDefault();
            return e is null ? "Undefined" : e.Description;
        }
    }
}

Sử dụng:

EnumX<Status>.Helper StatusCodes = new EnumX<Status>.Helper(new List<EnumX<Status>>()
        {
            new EnumX<Status>(Status.Success,"Operation was successful"),
            new EnumX<Status>(Status.Fail,"Operation failed"),
            new EnumX<Status>(Status.Pending,"Operation not complete. Please wait...")
        });

        Console.WriteLine(StatusCodes.GetDescription(Status.Pending));

-2

Tôi nghĩ cách tốt nhất (và dễ nhất) để giải quyết vấn đề của bạn là viết Phương pháp mở rộng cho enum của bạn:

public static string GetUserFriendlyString(this PublishStatusses status)
    {

    }

1
Ai đó đã 7 năm trước để nói rằng
Steven

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.