Enum ToString із зручними рядками


282

Мій перелік складається з таких значень:

private enum PublishStatusses{
    NotCompleted,
    Completed,
    Error
};

Хоча я можу вивести ці значення зручним для користувача способом.
Мені не потрібно мати можливість знову переходити від рядка до значення.


можливий дублікат C # String enums
nawfal

Відповіді:


350

Я використовую Descriptionатрибут із простору імен System.ComponentModel. Просто прикрасьте перерахунок:

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

Потім використовуйте цей код, щоб отримати його:

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
Цей приклад легше читати. stackoverflow.com/questions/1415140 / ...
RayLoveless

31
Я підозрюю, що для використання рефлексії, як описано в цьому рішенні, є значна ефективність. Код методу Віла, що використовує метод розширення ToFriendlyString, зрозуміти набагато простіше, і його ефективність також повинна бути надзвичайно швидкою.
хабади

1
Мені подобається версія, що @RayL пов’язана, оскільки вона лише додасть метод розширення до Enums. Якщо це все, що ви хочете використовувати для цього (як зазначено в ArgumentException, тоді немає ніяких причин для того, щоб метод був повністю загальним.
krillgar

4
Це означає, що кожному пережиткові потрібен власний метод розширення. Це більш загальне використання і вимагає більше роботи, але ви, мабуть, хочете кількісно оцінити, що означає "швидкий", перш ніж ми вирішимо про ефективність.
Рей Буйсен

2
@petar, яка працює, але не, якщо ви хочете, щоб друзі показували дружні рядки. MY_TYPE матиме підкреслення і не може бути налаштований.
Рей Буйсен

354

Я роблю це методами розширення:

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
Це набагато чіткіше, ніж відповідь "Атрибут". Приємно!
pennyrave

3
@pennyrave: Eh. Багато компонентів інтерфейсу очікують знайти та використовувати DisplayNameAttribute та DescriptionAttribute. Насправді зараз я використовую ці методи розширення, щоб легко отримати ці значення.

60
Проблема, яку я бачу в цьому, полягає в тому, що ви постійно пишете ці методи розширення. З механізмом атрибутів це простий спосіб його прикрасити і лише колись викликати один метод.
Рей Буйсен

5
Не знаєте, що ви маєте на увазі?
Рей Буйсен

9
На мій погляд, краще, щоб дозволити реалізації defaultсправи повернутися me.ToString()і надати лише виписки з перемикання випадків для значень enum, які ви хочете змінити. У вашому прикладі я розумію, що всі вони різні, але в реальних випадках використання, я підозрюю, що більшості значень enum одного слова буде достатньо, і ви будете надавати лише переопрацювання значень для перерахування на кілька слів.
Скотт

78

Можливо, мені щось не вистачає, але що не так із Enum.GetName?

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

редагувати: для зручних для користувача рядків вам потрібно пройти через .resource, щоб зробити інтернаціоналізацію / локалізацію, і, певно, було б краще використовувати фіксований ключ на основі ключа enum, ніж атрибут декоратора на тому ж самому.


12
Я повертає буквальне значення перерахунку, а не якесь зручне для користувача.
Борис Калленс

2
oic - ну є досить великий випадок, що вам доведеться пройти через бібліотеку рядкових ресурсів, виходячи з цього значення, тому що альтернатива (інтрибування декораторів) не підтримує I18N
annakata

1
У випадку I18N я б здійснив пошук методу GetDescription () в ресурсі lib для перекладеного рядка і повернувся до опису, а потім повернувся до прямого.
Борис Калленс

3
+1 для MyEnum.ToString () як ресурсний ключ для локалізації. я роблю це роками
jackvsworld

1
@annakata ми фактично розширили механізм атрибутів, щоб включити підтримку l18N, насправді це проста зміна.
Рей Буйсен

23

Я створив метод зворотного розширення, щоб перетворити опис назад у значення перерахунку:

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
Вибачте, але дякую, що намагаєтесь бути корисними! Хоча, оскільки це веб-сайт із питань запитання, відповіді мають бути спробою прямо відповісти на питання. І в питанні конкретно сказано: " Мені не потрібно мати можливість знову переходити від рядка до значення ". Ще раз дякую!
Джессі

8
Дякую за позитивну критику. Завжди важко бути новинкою на сайті та дізнатися про його культуру та нюанси. Я радий, що є такі люди, як ти, які прямо налаштували нових хлопців. Ще раз дякую за те, що не скидався на нового хлопця.
Брайан Річардсон

6
@Jesse І через 4 роки хтось із задоволенням знайде тут код bjrichardson! Так може бути веб-сайт із запитаннями, але це не означає, що запитання після отримання відповіді мертві.
Джон

18

Найпростішим рішенням тут є використання спеціального методу розширення (принаймні, у .NET 3.5 - ви можете просто перетворити його в статичний допоміжний метод для більш ранніх версій версій).

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

Я припускаю, що ви хочете повернути щось інше, ніж власне ім'я значення enum (яке ви можете отримати, просто зателефонувавши в ToString).


Хоча дійсно, мені більше подобається атрибут. Таким чином я можу розмістити свій метод tostring в окремій бібліотеці, в той час як розміщуючи власну строкову репрезентацію із самим перерахунком
Борис Калленс

1
Досить справедливо. Я припускаю, що однією з переваг цього методу є те, що ви можете включити аргумент із методом із зазначенням певної змінної стану, а потім змінити те, що рядкове подання повертається залежно від цього.
Нолдорін

1
Так, все залежить від обсягу методу, який я здогадуюсь. Хоча шлях атрибутів є більш загальним, ваше рішення більш локалізоване. Зрештою, це стосується потреб.
Борис Калленс

1
Ви можете розмістити методи розширення куди завгодно. Вам просто потрібно вказати його там, де ви хочете їх використовувати.

Так, але це означатиме, що цей метод розширення повинен бути переписаний кожен раз, коли ви вводите новий перелік, для якого ви хочете мати дружнє ім'я. Це також означатиме, що ВСІ ваші програми мають усі дружні імена для ВСІХ ваших інших програм ...
Борис Калленс

13

Цей інший пост - Java. Ви не можете помістити методи в Enums в C #.

просто зробіть щось подібне:

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

Якщо ви хочете використовувати різні значення відображення для значень enum, ви можете використовувати Атрибути та Відображення.


3
toString не є безпечним у всіх випадках - перерахунок з декількома записами з однаковим значенням (скажімо, для цілих перерахунків) поверне ключ першого відповідного значення, а не ключ перевіреного елемента, саме тому перевагу Enum.GetName
annakata

4
Ну, це було найпростішим рішенням для його конкретного перерахунку
Леммі

9

Найпростіший спосіб - просто включити цей клас розширення у свій проект, він буде працювати з будь-яким перерахунком у проекті:

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

Використання:

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

...

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

2
Таємниця, чому цей коментар не є прийнятим, або найбільш схваленим - ні рефлексія, ні зайві атрибути, ідеально підходять для простих ситуацій, де перелік уже добре названий. Ви можете зробити цю відповідь ще на крок і дозволити додавати пробіли між великими літерами перед поверненням "Мій Енум".
Вікс

12
Якщо перелік вже добре названий, немає необхідності в жодному методі розширення. Просто використовуйте існуючий метод ToString ().string result = "Result: " + ee;
Джон,

Це має бути найкращою відповіддю. Це працює для будь-якого перерахунку. Ви можете навіть реалізувати його за допомогою конкретного Enum, просто змінивши тип параметра Enum на фактичний Enum, на якому його використовувати.
Juanu Haedo

6
Ця відповідь та всі коментарі ігнорують оригінальний запит на розширений опис. Ви, хлопці, зовсім пропустили вправу, яка полягає в тому, щоб повернути щось інше, ніж значення ToString за замовчуванням. Я не скажу всі замітки до цієї відповіді тут, але я впевнений, що хочу.
TonyG

8

Деякі інші більш примітивні варіанти, які уникають класів / типів посилань:

  • Метод масиву
  • Вкладений метод Stru

Метод масиву

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

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

Використання

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

Вкладений метод Stru

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";
    }            
}

Використання

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

Оновлення (09.09.2018)

Гібрид методів розширення та перша методика, наведена вище.

Я вважаю за краще, щоб переліки визначалися там, де вони "належать" (найближче до джерела їх походження, а не в якомусь загальному, глобальному просторі імен).

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)" };
        }
    }
}

Метод розширення, здається, підходить для загальної області, і "локалізоване" визначення перерахунку тепер робить метод розширення більш багатослівним.

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

Приклад використання enum та його метод розширення.

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;
        }
    }
}

Примітка. Насправді я вирішив усунути Enumобгортку (і Nameмасив), оскільки найкраще, щоб рядки імен виходили з ресурсу (тобто конфігураційного файлу або БД), а не з жорсткого кодування, і тому що я в кінцевому підсумку помістив метод розширення в ViewModelsпростір імен (просто в іншому файлі "CommonVM.cs"). Плюс все .Idце стає відволікаючим і громіздким.

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;
            }
        }
    }   
}

Приклад використання enum та його метод розширення.

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 голосів: Це рішення зберігає синтаксис Enum і елегантно вирішує проблему без роздумів або складного коду, тому +1 там. Але він втрачає риси самих Енумів. Отже, хоча ІМО - це хороший варіант, він не відповідає на власне питання і отримує -1. Чистий 0. Вибачте, у нас немає способу записати це краще в SO.
TonyG

@TonyG Ярмарок досить. Пропустивши кілька запитань щодо оцінки навичок pluarlsight.com .net, я почав розуміти, наскільки глибокий перелік C # enum, тому, ймовірно, було б принаймні знати про їхні можливості, перш ніж вирішити, яку методологію застосовувати (особливо для розповсюдженого використання, рефакторингу може бути трохи часу;).
Саміс

7

Ви можете використовувати HUMANIZER пакет з гуманізацією Enums Possiblity. Приклад:

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

то ви можете використовувати Humanizeметод розширення на enum безпосередньо:

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)

Він також використовує відображення і не кешований. github.com/Humanizr/Humanizer/blob/…
Конрад

Це буде так само повільно, як рішення у першій відповіді Рея
Конрада

5

Що стосується Рея Буйсена, в коді є помилка: Enum ToString з зручними рядками

Потрібно враховувати кілька атрибутів на значення 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
Упущення перевірки на кілька атрибутів Опис призначено навмисно. Якщо переліків два, і ви використовуєте для створення опису, я б хотів подумати, що це виняткова обставина. Я думаю, що фактична помилка полягає в тому, що я не роблю Single (), щоб викинути виняток. Інакше весь підпис методу не має сенсу. GetDescription ()? Який опис? Сукупність?
Рей Буйсен

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
Завжди приємно написати текст, в якому пояснюється, чому це повинно працювати, і чому ОП не було.
фаберест

Просто конвенції коду FYI, C # хочуть локальних змінних та параметрів методу з малої літери. Один виняток - thisпараметр у методах розширення, який можна побачити Thisв багатьох прикладах в Інтернеті. Викликаючи його так, як його тип, як і ви ( Enum Enum) зробить код менш читабельним.
Массіміліано Краус

4

Замість enum використовуйте статичний клас.

замінити

private enum PublishStatuses{
    NotCompleted,
    Completed,
    Error
};

з

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

він буде використовуватися так

PublishStatuses.NotCompleted; // "Not Completed"

Проблема, використовуючи верхні рішення "методу розширення":

Приватний перелік часто використовується всередині іншого класу. Рішення методу розширення там не дійсне, оскільки воно повинно бути у власному класі. Це рішення може бути приватним і вбудовуватися в інший клас.


2

Я випадково є шанувальником VB.NET, тому ось моя версія, що поєднує метод DescriptionAttribute з методом розширення. По-перше, результати:

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

Основний матеріал: перерахунок під назвою EnumType з трьома значеннями V1, V2 і V3. "Магія" відбувається у виклику Console.WriteLine в Sub Main (), де останній аргумент просто v.Description. Це повертає "Один" для V1, "V2" для V2 і "Три" для V3. Цей метод опису насправді є методом розширення, визначеним в іншому модулі під назвою 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

Оскільки пошук атрибутів опису, який використовується, Reflectionвідбувається повільно, пошук також кешується в приватному режимі Dictionary, який заповнюється на вимогу.

(Вибачте за рішення VB.NET - це повинно бути досить просто, щоб перевести його на C #, а мій C # іржавий на нових предметах, таких як розширення)


2

Чистий підсумок вищезазначених пропозицій із зразком:

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

ВИКОРИСТАННЯ:

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 # є атрибут [Description ("")], чому б не використовувати цей?
Стефан Коен

Звичайно, використання [Опис ("")] - це шлях. Але я хотів, щоб зразок був повним.
підкреслюємо

2

Використовуйте Enum.GetName

З вищенаведеного посилання ...

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

Відповідно до цієї документації: https://docs.microsoft.com/pt-br/dotnet/api/system.enum.tostring?view=netframework-4.8

Можна просто перетворити нумератор у рядок, використовуючи такий формат:

public enum Example
{
    Example1,
    Example2
}

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

//Outputs: "Example1"

Ви можете переглянути всі можливі формати за цим посиланням: https://docs.microsoft.com/pt-br/dotnet/api/system.string?view=netframework-4.8


1

Це оновлення коду Рея Буйсена, який використовує загальний метод GetCustomAttributes та LINQ, щоб зробити речі трохи охайнішими.

    /// <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();
    }   

Якщо ви не зрозуміли, для чого вам це потрібно загальним? Якщо ви збираєтеся використовувати рефлексію?
Лі Лув'є

@LeeLouviere Головним чином, щоб уникнути боксу, коли структура (тип значення) передається як параметр.
Річард Ентоні Хайн

1
замість numerationValue.GetType () використовуйте: typeof (T).
Слава

1
Величезне вдосконалення в одному рядку щодо прийнятої відповіді без (YMMV) втрати читабельності. Так, з typeof (T).
TonyG

1

Ще більш чіткий підсумок:

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();
    }
}

Таке ж використання, як описано підкреслення.


0

Для прапорів, перерахувань у тому числі.

    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

Якщо ви просто хочете додати пробіл між словами, це так само просто

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

0

Я використовую загальний клас для зберігання пар enum / description та вкладений клас помічників для отримання опису.

перерахування :

enum Status { Success, Fail, Pending }

Родовий клас:

Примітка: Так як загальний клас не може бути обмежений у перерахуванні я стримуючий по структурі , а й перевірки для перерахування в конструкторі.

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;
        }
    }
}

Використання:

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

Я думаю, що найкращий (і найпростіший) спосіб вирішити вашу проблему - написати метод розширення для перерахунку:

public static string GetUserFriendlyString(this PublishStatusses status)
    {

    }

1
Хтось був на 7 років раніше, щоб стверджувати, що
Стівен

-3

Якщо ви хочете щось повністю настроюється, спробуйте моє рішення тут:

http://www.kevinwilliampang.com/post/Mapping-Enums-To-Strings-and-Strings-to-Enums-in-NET.aspx

По суті, публікація визначає, як приєднати атрибути Опис до кожного з ваших переліків і надає загальний спосіб зіставлення від перерахунку до опису.


1
А зараз сайт вниз.
Нік Фостер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.