Строковое представление Enum

843

У меня есть следующее перечисление:

public enum AuthenticationMethod
{
    FORMS = 1,
    WINDOWSAUTHENTICATION = 2,
    SINGLESIGNON = 3
}

Однако проблема в том, что мне нужно слово "FORMS", когда я запрашиваю AuthenticationMethod.FORMS, а не идентификатор 1.

Я нашел следующее решение для этой проблемы (ссылка):

Сначала мне нужно создать настраиваемый атрибут под названием "StringValue":

public class StringValue : System.Attribute
{
    private readonly string _value;

    public StringValue(string value)
    {
        _value = value;
    }

    public string Value
    {
        get { return _value; }
    }

}

Затем я могу добавить этот атрибут в свой счетчик:

public enum AuthenticationMethod
{
    [StringValue("FORMS")]
    FORMS = 1,
    [StringValue("WINDOWS")]
    WINDOWSAUTHENTICATION = 2,
    [StringValue("SSO")]
    SINGLESIGNON = 3
}

И, конечно, мне нужно что-то получить в этом StringValue:

public static class StringEnum
{
    public static string GetStringValue(Enum value)
    {
        string output = null;
        Type type = value.GetType();

        //Check first in our cached results...

        //Look for our 'StringValueAttribute' 

        //in the field custom attributes

        FieldInfo fi = type.GetField(value.ToString());
        StringValue[] attrs =
           fi.GetCustomAttributes(typeof(StringValue),
                                   false) as StringValue[];
        if (attrs.Length > 0)
        {
            output = attrs[0].Value;
        }

        return output;
    }
}

Хорошо, теперь у меня есть инструменты для получения строкового значения для счетчика. Затем я могу использовать его следующим образом:

string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);

Хорошо, теперь все они работают как шарм, но я нахожу его очень много работы. Мне было интересно, есть ли лучшее решение для этого.

Я также пробовал что-то со словарем и статическими свойствами, но это было не лучше.

  • 8
    Ницца! Я могу использовать это для перевода значений перечисления в локализованные строки.
  • 5
    Хотя вы можете найти это долго, но на самом деле это довольно гибкий способ для других вещей. Как отметил один из моих коллег, во многих случаях это можно использовать для замены помощников Enum, которые отображают коды базы данных на значения enum и т. Д.
Показать ещё 7 комментариев
Теги:
string
enums
enumerator

34 ответа

821
Лучший ответ

Попробуйте шаблон типа-safe-enum.

public sealed class AuthenticationMethod {

    private readonly String name;
    private readonly int value;

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (3, "SSN");        

    private AuthenticationMethod(int value, String name){
        this.name = name;
        this.value = value;
    }

    public override String ToString(){
        return name;
    }

}

Обновление Явное (или неявное) преобразование типа может быть выполнено с помощью

  • добавление статического поля с отображением

    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    
    • n.b. Чтобы инициализация полей "enum member" не выбрасывала исключение NullReferenceException при вызове конструктора экземпляра, обязательно поместите поле "Словарь" перед полями "enum member" в вашем классе. Это связано с тем, что инициализаторы статического поля вызывают в порядке объявления и перед статическим конструктором, создавая странную и необходимую, но запутанную ситуацию, когда конструктор экземпляра можно вызвать до того, как все статические поля были инициализированы и до вызова статического конструктора.
  • заполнение этого сопоставления в конструкторе экземпляра

    instance[name] = this;
    
  • и добавив пользовательский оператор преобразования типов

    public static explicit operator AuthenticationMethod(string str)
    {
        AuthenticationMethod result;
        if (instance.TryGetValue(str, out result))
            return result;
        else
            throw new InvalidCastException();
    }
    
  • 16
    Это выглядит как перечисление, но это не перечисление. Я могу представить, что это вызывает некоторые интересные проблемы, если люди начинают пытаться сравнивать AuthenticationMethods. Вам, вероятно, нужно перегружать различные операторы равенства.
  • 36
    @Ant: я не должен. Поскольку у нас есть только один экземпляр каждого метода AuthenticationMethod, равенство ссылок, унаследованное от Object, работает нормально.
Показать ещё 30 комментариев
202

Использовать метод

Enum.GetName(Type MyEnumType,  object enumvariable)  

как в (Предположим, что Shipper - определенный Enum)

Shipper x = Shipper.FederalExpress;
string s = Enum.GetName(typeof(Shipper), x);

В классе Enum также есть множество других статических методов...

  • 5
    Именно так. Я сделал собственный атрибут для описания строки, но это потому, что я хочу удобную для пользователя версию (с пробелами и другими специальными символами), которую можно легко привязать к ComboBox или тому подобному.
  • 5
    Enum.GetName отражает имена полей в перечислении - так же, как .ToString (). Если производительность является проблемой, это может быть проблемой. Я не стал бы беспокоиться об этом, если вы не конвертируете множество перечислений.
Показать ещё 10 комментариев
77

Вы можете ссылаться на имя, а не на значение, используя ToString()

Console.WriteLine("Auth method: {0}", AuthenticationMethod.Forms.ToString());

Документация находится здесь:

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

... и если вы назовете свои перечисления в Pascal Case (как и я - например, ThisIsMyEnumValue = 1 и т.д.), вы можете использовать очень простое регулярное выражение для печати дружественной формы:

static string ToFriendlyCase(this string EnumString)
{
    return Regex.Replace(EnumString, "(?!^)([A-Z])", " $1");
}

который можно легко вызвать из любой строки:

Console.WriteLine("ConvertMyCrazyPascalCaseSentenceToFriendlyCase".ToFriendlyCase());

Выходы:

Преобразование моего сумасшедшего случая Паскаля в дружественный случай

Это экономит всю дорогу по домам, создавая настраиваемые атрибуты и привязывая их к вашим перечислениям или используя таблицы поиска, чтобы жениться на значении перечисления с дружественной строкой и, самое главное, управлять ею и может использоваться в любой строке Case Pascal который бесконечно более многоразовый. Конечно, это не позволяет вам иметь другое дружественное имя, чем ваше перечисление, которое предоставляет ваше решение.

Мне нравится ваше оригинальное решение, хотя для более сложных сценариев. Вы можете сделать свое решение еще на один шаг и сделать GetStringValue расширением метода вашего перечисления, а затем вам не нужно будет ссылаться на него как StringEnum.GetStringValue...

public static string GetStringValue(this AuthenticationMethod value)
{
  string output = null;
  Type type = value.GetType();
  FieldInfo fi = type.GetField(value.ToString());
  StringValue[] attrs = fi.GetCustomAttributes(typeof(StringValue), false) as StringValue[];
  if (attrs.Length > 0)
    output = attrs[0].Value;
  return output;
}

Затем вы можете легко получить доступ к нему из своего экземпляра перечисления:

Console.WriteLine(AuthenticationMethod.SSO.GetStringValue());
  • 2
    Это не поможет, если «дружественному имени» нужен пробел. Такие как «Аутентификация с помощью форм»
  • 4
    Поэтому убедитесь, что перечисление названо заглавными буквами, такими как FormsAuthentication, и вставьте пробел перед любыми заглавными буквами, которых нет в начале. Это не ракетостроение, чтобы вставить пробел в строку ...
Показать ещё 3 комментария
64

К сожалению, отражение для получения атрибутов в перечислениях довольно медленно:

Посмотрите на этот вопрос: Кто-нибудь знает быстрый способ получить настраиваемые атрибуты для значения перечисления?

.ToString() слишком медленный и для перечислений.

Вы можете писать методы расширения для перечислений:

public static string GetName( this MyEnum input ) {
    switch ( input ) {
        case MyEnum.WINDOWSAUTHENTICATION:
            return "Windows";
        //and so on
    }
}

Это не очень удобно, но будет быстрым и не требует отражения для атрибутов или имени поля.


Обновление С# 6

Если вы можете использовать С# 6, то новый оператор nameof работает для перечислений, поэтому nameof(MyEnum.WINDOWSAUTHENTICATION) будет преобразован в "WINDOWSAUTHENTICATION" во время компиляции, сделав его самым быстрым способом получить имена переименований.

Обратите внимание, что это преобразует явное перечисление в встроенную константу, поэтому она не работает для перечислений, которые у вас есть в переменной. Итак:

nameof(AuthenticationMethod.FORMS) == "FORMS"

Но...

var myMethod = AuthenticationMethod.FORMS;
nameof(myMethod) == "myMethod"
  • 24
    Вы можете получить значения атрибутов один раз и поместить их в словарь <MyEnum, строка>, чтобы сохранить декларативный аспект.
  • 1
    Да, это то, что мы сделали в приложении с множеством перечислений, когда узнали, что отражение было узким местом.
Показать ещё 8 комментариев
51

Я использую метод расширения:

public static class AttributesHelperExtension
    {
        public static string ToDescription(this Enum value)
        {
            var da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return da.Length > 0 ? da[0].Description : value.ToString();
        }
}

Теперь украсьте enum с помощью

public enum AuthenticationMethod
{
    [Description("FORMS")]
    FORMS = 1,
    [Description("WINDOWSAUTHENTICATION")]
    WINDOWSAUTHENTICATION = 2,
    [Description("SINGLESIGNON ")]
    SINGLESIGNON = 3
}

Когда вы вызываете

AuthenticationMethod.FORMS.ToDescription() вы получите "FORMS".

  • 0
    это самое короткое!
  • 1
    Мне пришлось добавить using System.ComponentModel; Кроме того, этот метод работает, только если вы хотите, чтобы значение String совпадало с именем Enum. ОП хотел другое значение.
Показать ещё 2 комментария
37

Просто используйте метод ToString()

public enum any{Tomato=0,Melon,Watermelon}

Чтобы ссылаться на строку Tomato, просто используйте

any.Tomato.ToString();
  • 0
    Вот это да. Это было просто. Я знаю, что ОП хотел добавить пользовательские описания строк, но это то, что мне было нужно. Я должен был попробовать это, оглядываясь назад, но я пошел по маршруту Enum.GetName.
  • 7
    Почему все остальные слишком усложняют это?
Показать ещё 5 комментариев
25

Я использую атрибут Description из пространства имен System.ComponentModel. Просто украсьте перечисление, а затем используйте этот код, чтобы получить его:

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

        }

В качестве примера:

public enum Cycle : int
{        
   [Description("Daily Cycle")]
   Daily = 1,
   Weekly,
   Monthly
}

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

23

Очень простое решение для этого с .Net 4.0 и выше. Никакой другой код не нужен.

public enum MyStatus
{
    Active = 1,
    Archived = 2
}

Чтобы получить строку только для использования:

MyStatus.Active.ToString("f");

или

MyStatus.Archived.ToString("f");`

Значение будет "Активно" или "Архивировано".

Чтобы увидеть различные строковые форматы ( "f" сверху) при вызове Enum.ToString см. эту страницу Строка формата перечисления страница

21

Мне очень нравится ответ Jakub Šturc, но недостатком является то, что вы не можете использовать его с помощью оператора switch-case. Здесь немного измененная версия его ответа, которая может быть использована с оператором switch:

public sealed class AuthenticationMethod
{
    #region This code never needs to change.
    private readonly string _name;
    public readonly Values Value;

    private AuthenticationMethod(Values value, String name){
        this._name = name;
        this.Value = value;
    }

    public override String ToString(){
        return _name;
    }
    #endregion

    public enum Values
    {
        Forms = 1,
        Windows = 2,
        SSN = 3
    }

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (Values.Forms, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (Values.Windows, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (Values.SSN, "SSN");
}

Итак, вы получаете все преимущества ответа Jakub Šturc, плюс мы можем использовать его с инструкцией switch следующим образом:

var authenticationMethodVariable = AuthenticationMethod.FORMS;  // Set the "enum" value we want to use.
var methodName = authenticationMethodVariable.ToString();       // Get the user-friendly "name" of the "enum" value.

// Perform logic based on which "enum" value was chosen.
switch (authenticationMethodVariable.Value)
{
    case authenticationMethodVariable.Values.Forms: // Do something
        break;
    case authenticationMethodVariable.Values.Windows: // Do something
        break;
    case authenticationMethodVariable.Values.SSN: // Do something
        break;      
}
  • 0
    Более коротким решением было бы удалить перечисления {} и вместо этого вести статический подсчет количества созданных вами перечислений. Это также дает то преимущество, что вам не нужно добавлять новый экземпляр в список перечислений. Например, public static int nextAvailable { get; private set; } затем в конструкторе this.Value = nextAvailable++;
  • 0
    Интересная идея @kjhf. Однако меня беспокоит то, что если кто-то переупорядочит код, то значение, присвоенное значениям перечисления, также может измениться. Например, это может привести к получению неверного значения перечисления при сохранении значения перечисления в файл / базу данных, изменении порядка строк «new AuthenticationMethod (...)» (например, одна удаляется), а затем снова запустить приложение и получить значение enum из файла / базы данных; значение enum может не совпадать с AuthenticationMethod, который был изначально сохранен.
Показать ещё 3 комментария
11

Я использую комбинацию из нескольких предложений выше, в сочетании с некоторым кэшированием. Теперь у меня появилась идея из некоторого кода, который я нашел где-то в сети, но я не могу ни помнить, где я его нашел, или найти его. Поэтому, если кто-либо найдет что-то похожее, прокомментируйте его с помощью атрибуции.

В любом случае, использование включает в себя преобразователи типов, поэтому, если вы привязываетесь к пользовательскому интерфейсу, он "просто работает". Вы можете расширить шаблон Jakub для быстрого поиска кода, инициализируя из преобразователя типов в статические методы.

Основное использование будет выглядеть следующим образом:

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
    // The custom type converter will use the description attribute
    [Description("A custom description")]
    ValueWithCustomDescription,

   // This will be exposed exactly.
   Exact
}

Ниже приведен код конвертера пользовательского типа перечисления:

public class CustomEnumTypeConverter<T> : EnumConverter
    where T : struct
{
    private static readonly Dictionary<T,string> s_toString = 
      new Dictionary<T, string>();

    private static readonly Dictionary<string, T> s_toValue = 
      new Dictionary<string, T>();

    private static bool s_isInitialized;

    static CustomEnumTypeConverter()
    {
        System.Diagnostics.Debug.Assert(typeof(T).IsEnum,
          "The custom enum class must be used with an enum type.");
    }

    public CustomEnumTypeConverter() : base(typeof(T))
    {
        if (!s_isInitialized)
        {
            Initialize();
            s_isInitialized = true;
        }
    }

    protected void Initialize()
    {
        foreach (T item in Enum.GetValues(typeof(T)))
        {
            string description = GetDescription(item);
            s_toString[item] = description;
            s_toValue[description] = item;
        }
    }

    private static string GetDescription(T optionValue)
    {
        var optionDescription = optionValue.ToString();
        var optionInfo = typeof(T).GetField(optionDescription);
        if (Attribute.IsDefined(optionInfo, typeof(DescriptionAttribute)))
        {
            var attribute = 
              (DescriptionAttribute)Attribute.
                 GetCustomAttribute(optionInfo, typeof(DescriptionAttribute));
            return attribute.Description;
        }
        return optionDescription;
    }

    public override object ConvertTo(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, 
       object value, Type destinationType)
    {
        var optionValue = (T)value;

        if (destinationType == typeof(string) && 
            s_toString.ContainsKey(optionValue))
        {
            return s_toString[optionValue];
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, object value)
    {
        var stringValue = value as string;

        if (!string.IsNullOrEmpty(stringValue) && s_toValue.ContainsKey(stringValue))
        {
            return s_toValue[stringValue];
        }

        return base.ConvertFrom(context, culture, value);
    }
}

}

10

В вашем вопросе вы никогда не говорили, что вам действительно нужно числовое значение перечисления где угодно.

Если вам нет и просто нужно перечисление строки типа (которое не является интегральным типом, поэтому не может быть базой перечисления), вот способ:

    static class AuthenticationMethod
    {
        public static readonly string
            FORMS = "Forms",
            WINDOWSAUTHENTICATION = "WindowsAuthentication";
    }

вы можете использовать тот же синтаксис, что и перечисление, чтобы ссылаться на него

if (bla == AuthenticationMethod.FORMS)

Это будет немного медленнее, чем с числовыми значениями (сравнение строк вместо чисел), но с плюсовой стороны он не использует отражение (медленное) для доступа к строке.

  • 0
    Это сработало для меня! (У)
  • 0
    если вы используете «const» вместо «static readonly», тогда вы можете использовать значения в качестве меток регистра в выражении switch.
10

Как и большинство из вас, мне очень понравился выбранный ответ Jakub Šturc, но мне также очень нравится копировать-вставлять код и пытаться сделать это как можно меньше как я могу.

Итак, я решил, что мне нужен класс EnumBase, из которого большинство функций наследуется/встроено, оставляя меня сосредоточиться на содержании, а не на поведении.

Основная проблема этого подхода основана на том факте, что хотя значения Enum являются экземплярами, безопасными для типов, взаимодействие происходит со статической реализацией типа Enum Class. Поэтому, немного помогая магии дженериков, я думаю, что, наконец, получил правильное сочетание. Надеюсь, кто-то найдет это полезным, как я.

Я начну с примера Jakub, но используя наследование и дженерики:

public sealed class AuthenticationMethod : EnumBase<AuthenticationMethod, int>
{
    public static readonly AuthenticationMethod FORMS =
        new AuthenticationMethod(1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION =
        new AuthenticationMethod(2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON =
        new AuthenticationMethod(3, "SSN");

    private AuthenticationMethod(int Value, String Name)
        : base( Value, Name ) { }
    public new static IEnumerable<AuthenticationMethod> All
    { get { return EnumBase<AuthenticationMethod, int>.All; } }
    public static explicit operator AuthenticationMethod(string str)
    { return Parse(str); }
}

И вот базовый класс:

using System;
using System.Collections.Generic;
using System.Linq; // for the .AsEnumerable() method call

// E is the derived type-safe-enum class
// - this allows all static members to be truly unique to the specific
//   derived class
public class EnumBase<E, T> where E: EnumBase<E, T>
{
    #region Instance code
    public T Value { get; private set; }
    public string Name { get; private set; }

    protected EnumBase(T EnumValue, string Name)
    {
        Value = EnumValue;
        this.Name = Name;
        mapping.Add(Name, this);
    }

    public override string ToString() { return Name; }
    #endregion

    #region Static tools
    static private readonly Dictionary<string, EnumBase<E, T>> mapping;
    static EnumBase() { mapping = new Dictionary<string, EnumBase<E, T>>(); }
    protected static E Parse(string name)
    {
        EnumBase<E, T> result;
        if (mapping.TryGetValue(name, out result))
        {
            return (E)result;
        }

        throw new InvalidCastException();
    }
    // This is protected to force the child class to expose it own static
    // method.
    // By recreating this static method at the derived class, static
    // initialization will be explicit, promising the mapping dictionary
    // will never be empty when this method is called.
    protected static IEnumerable<E> All
    { get { return mapping.Values.AsEnumerable().Cast<E>(); } }
    #endregion
}
  • 0
    Вы можете вызвать производный статический конструктор из базового статического конструктора. Я все еще смотрю на это, но до сих пор я не нашел никаких проблем с ним: stackoverflow.com/questions/55290034/…
9

Как я решил это как метод расширения:

using System.ComponentModel;
public static string GetDescription(this Enum value)
{
    var descriptionAttribute = (DescriptionAttribute)value.GetType()
        .GetField(value.ToString())
        .GetCustomAttributes(false)
        .Where(a => a is DescriptionAttribute)
        .FirstOrDefault();

    return descriptionAttribute != null ? descriptionAttribute.Description : value.ToString();
}

Enum:

public enum OrderType
{
    None = 0,
    [Description("New Card")]
    NewCard = 1,
    [Description("Reload")]
    Refill = 2
}

Использование (где o.OrderType - свойство с тем же именем, что и перечисление):

o.OrderType.GetDescription()

Что дает мне строку "Новая карта" или "Перезагрузка" вместо фактического значения перечисления NewCard и Refill.

  • 0
    Для полноты вы должны включить копию вашего класса DescriptionAttribute.
  • 3
    Берни, DescriptionAttribute находится в System.ComponentModel
9

Я согласен с Кейтом, но я не могу проголосовать (пока).

Я использую статический метод и инструкцию swith, чтобы вернуть именно то, что я хочу. В базе данных я храню tinyint, и мой код использует только фактическое перечисление, поэтому строки предназначены для требований пользовательского интерфейса. После многочисленных испытаний это привело к лучшей производительности и большему контролю над выходом.

public static string ToSimpleString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "ComplexForms";
             break;
     }
}

public static string ToFormattedString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "Complex Forms";
             break;
     }
}

Однако, по некоторым данным, это приводит к возможному кошмару обслуживания и запаху кода. Я стараюсь следить за перечислениями, которые длинные и много перечислений, или те, которые часто меняются. В противном случае это было отличным решением для меня.

7

Если вы пришли сюда, чтобы реализовать простой "Enum", но значения которого представляют собой строки вместо int, вот простейшее решение:

    public sealed class MetricValueList
    {
        public static readonly string Brand = "A4082457-D467-E111-98DC-0026B9010912";
        public static readonly string Name = "B5B5E167-D467-E111-98DC-0026B9010912";
    }

Реализация:

var someStringVariable = MetricValueList.Brand;
  • 2
    Вероятно, лучше сделать переменные постоянными, а не использовать static readonly .
  • 1
    Констант не подходит для общедоступных классов, так как они запекаются во время компиляции, вы не можете заменить стороннюю DLL-библиотеку, не перекомпилировав весь код с константами. Смещение производительности conts против статического readonly незначительно.
6

Когда я столкнулся с этой проблемой, есть несколько вопросов, на которые я пытаюсь сначала найти ответы:

  • Являются ли имена моих значений enum достаточно дружественными для этой цели или мне нужно предоставить более дружественные?
  • Нужно ли мне туда и обратно? То есть, мне нужно будет принимать текстовые значения и анализировать их в значениях перечисления?
  • Это что-то, что мне нужно сделать для многих перечислений в моем проекте или только один?
  • Какие элементы пользовательского интерфейса я буду представлять эту информацию, в частности, я буду привязываться к пользовательскому интерфейсу или использовать листы свойств?
  • Нужно ли это локализуемо?

Самый простой способ сделать это - Enum.GetValue (и поддерживать круговое отключение с помощью Enum.Parse). Также часто стоит построить TypeConverter, как предлагает Стив Митчем, для поддержки привязки интерфейса. (Нет необходимости создавать a TypeConverter, когда вы используете листы свойств, что является одной из приятных вещей о листах свойств. Хотя лорд знает, что у них есть свои проблемы.)

В общем случае, если ответы на вышеуказанные вопросы подсказывают, что это не сработает, следующим шагом будет создание и заполнение статического Dictionary<MyEnum, string> или, возможно, Dictionary<Type, Dictionary<int, string>>. Я склонен пропускать промежуточный этап decorate-the-code-with-attributes, потому что из-за того, что обычно происходит после щуки, необходимо изменить дружественные значения после развертывания (часто, но не всегда, из-за локализации).

5

Я хотел опубликовать это как комментарий к цитируемому ниже сообщению, но не смог, потому что у меня недостаточно отзывов, поэтому, пожалуйста, не голосуйте. Код содержал ошибку, и я хотел указать на это тем, кто пытается использовать это решение:

[TypeConverter(typeof(CustomEnumTypeConverter(typeof(MyEnum))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,
  // This will be exposed exactly.
  Exact
}

должен быть

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,

  // This will be exposed exactly.
  Exact
}

Brillant!

4

Мой вариант

public struct Colors
{
    private String current;

    private static string red = "#ff0000";
    private static string green = "#00ff00";
    private static string blue = "#0000ff";

    private static IList<String> possibleColors; 

    public static Colors Red { get { return (Colors) red; } }
    public static Colors Green { get { return (Colors) green; } }
    public static Colors Blue { get { return (Colors) blue; } }

    static Colors()
    {
        possibleColors = new List<string>() {red, green, blue};
    }

    public static explicit operator String(Colors value)
    {
        return value.current;
    }

    public static explicit operator Colors(String value)
    {
        if (!possibleColors.Contains(value))
        {
            throw new InvalidCastException();
        }

        Colors color = new Colors();
        color.current = value;
        return color;
    }

    public static bool operator ==(Colors left, Colors right)
    {
        return left.current == right.current;
    }

    public static bool operator !=(Colors left, Colors right)
    {
        return left.current != right.current;
    }

    public bool Equals(Colors other)
    {
        return Equals(other.current, current);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (obj.GetType() != typeof(Colors)) return false;
        return Equals((Colors)obj);
    }

    public override int GetHashCode()
    {
        return (current != null ? current.GetHashCode() : 0);
    }

    public override string ToString()
    {
        return current;
    }
}

Код выглядит немного уродливым, но использование этой структуры довольно презентабельно.

Colors color1 = Colors.Red;
Console.WriteLine(color1); // #ff0000

Colors color2 = (Colors) "#00ff00";
Console.WriteLine(color2); // #00ff00

// Colors color3 = "#0000ff"; // Compilation error
// String color4 = Colors.Red; // Compilation error

Colors color5 = (Colors)"#ff0000";
Console.WriteLine(color1 == color5); // True

Colors color6 = (Colors)"#00ff00";
Console.WriteLine(color1 == color6); // False

Кроме того, я думаю, если бы потребовалось много таких перечислений, можно было бы использовать генерацию кода (например, T4).

3

для меня прагматический подход - это класс внутри класса, образец:

public class MSEModel
{
    class WITS
    {
        public const string DATE = "5005";
        public const string TIME = "5006";
        public const string MD = "5008";
        public const string ROP = "5075";
        public const string WOB = "5073";
        public const string RPM = "7001";
... 
    }
3

Если вы думаете о проблеме, которую мы пытаемся решить, это не переименование, которое нам нужно вообще. Нам нужен объект, который позволяет связать определенное количество значений с eachother; другими словами, определить класс.

Якуб Šturc тип безопасного типа перечисления - лучший вариант, который я вижу здесь.

Посмотрите на это:

  • Он имеет частный конструктор, поэтому только класс может определять допустимые значения.
  • Это запечатанный класс, поэтому значения не могут быть изменены через наследование.
  • Это безопасный тип, позволяющий вашим методам требовать только этот тип.
  • Невозможно отразить производительность, полученную при доступе к значениям.
  • И, наконец, его можно изменить, чтобы связать более двух полей вместе, например, Имя, Описание и числовое значение.
3

Вариант 1:

public sealed class FormsAuth
{
     public override string ToString{return "Forms Authtentication";}
}
public sealed class WindowsAuth
{
     public override string ToString{return "Windows Authtentication";}
}

public sealed class SsoAuth
{
     public override string ToString{return "SSO";}
}

а затем

object auth = new SsoAuth(); //or whatever

//...
//...
// blablabla

DoSomethingWithTheAuth(auth.ToString());

Вариант 2:

public enum AuthenticationMethod
{
        FORMS = 1,
        WINDOWSAUTHENTICATION = 2,
        SINGLESIGNON = 3
}

public class MyClass
{
    private Dictionary<AuthenticationMethod, String> map = new Dictionary<AuthenticationMethod, String>();
    public MyClass()
    {
         map.Add(AuthenticationMethod.FORMS,"Forms Authentication");
         map.Add(AuthenticationMethod.WINDOWSAUTHENTICATION ,"Windows Authentication");
         map.Add(AuthenticationMethod.SINGLESIGNON ,"SSo Authentication");
    }
}
2

старый пост, но...

Ответ на это может быть очень простым. Используйте Функция Enum.ToString()

Есть 6 перегрузок этой функции, вы можете использовать Enum.Tostring( "F" ) или Enum.ToString(), чтобы вернуть значение строки. Не нужно беспокоиться ни о чем другом. Ниже приведена рабочая демонстрация

Обратите внимание, что это решение может не работать для всех компиляторов (эта демонстрация не работает должным образом), но по крайней мере она работает для последнего компилятора.

2

Если я правильно понимаю вас, вы можете просто использовать .ToString() для извлечения имени перечисления из значения (Предположим, что он уже включен как Enum); Если у вас был голый int (скажем, из базы данных или что-то еще), вы можете сначала перенести его в перечисление. Оба метода ниже дадут вам имя перечисления.

AuthenticationMethod myCurrentSetting = AuthenticationMethod.FORMS;
Console.WriteLine(myCurrentSetting); // Prints: FORMS
string name = Enum.GetNames(typeof(AuthenticationMethod))[(int)myCurrentSetting-1];
Console.WriteLine(name); // Prints: FORMS

Имейте в виду, однако, второй метод предполагает, что вы используете ints, а ваш индекс основан на 1 (не на основе 0). Функция GetNames также довольно тяжела для сравнения, вы генерируете целый массив каждый раз, когда он вызывал. Как вы можете видеть в первом методе,.ToString() фактически называется неявно. Оба они уже упоминаются в ответах, конечно, я просто пытаюсь разъяснить различия между ними.

2

Здесь много замечательных ответов, но в моем случае не разрешило то, что я хотел, из "переименования строк", которое было:

  • Используется в операторе switch, например, switch (myEnum)
  • Может использоваться в параметрах функции, например. foo (тип myEnum)
  • Можно ссылаться, например. myEnum.FirstElement
  • Я могу использовать строки, например. foo ( "FirstElement" ) == foo (myEnum.FirstElement)

1,2 и 4 действительно могут быть решены с помощью С# Typedef строки (поскольку строки переключаются в С#)

3 может быть решена статическими константными строками. Поэтому, если у вас одинаковые потребности, это самый простой способ:

public sealed class Types
{

    private readonly String name;

    private Types(String name)
    {
        this.name = name;

    }

    public override String ToString()
    {
        return name;
    }

    public static implicit operator Types(string str)
    {
        return new Types(str);

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }


    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";
    public const string Folder = "Folder";
    #endregion

}

Это позволяет, например:

    public TypeArgs(Types SelectedType)
    {
        Types SelectedType = SelectedType
    }

и

public TypeObject CreateType(Types type)
    {
        switch (type)
        {

            case Types.ImageType:
              //
                break;

            case Types.DataType:
             //
                break;

        }
    }

Если CreateType может быть вызван со строкой или типом. Однако недостатком является то, что любая строка автоматически является допустимым enum, это может быть изменено, но тогда для этого потребуется какая-то функция init... или, возможно, сделать их явным, литые внутренние?

Теперь, если значение int было важно для вас (возможно, для скорости сравнения), вы могли бы использовать некоторые идеи от Jakub Šturc фантастический ответ и сделать что-то немного сумасшедшее, это мой удар в него:

    public sealed class Types
{
    private static readonly Dictionary<string, Types> strInstance = new Dictionary<string, Types>();
    private static readonly Dictionary<int, Types> intInstance = new Dictionary<int, Types>();

    private readonly String name;
    private static int layerTypeCount = 0;
    private int value;
    private Types(String name)
    {
        this.name = name;
        value = layerTypeCount++;
        strInstance[name] = this;
        intInstance[value] = this;
    }

    public override String ToString()
    {
        return name;
    }


    public static implicit operator Types(int val)
    {
        Types result;
        if (intInstance.TryGetValue(val, out result))
            return result;
        else
            throw new InvalidCastException();
    }

    public static implicit operator Types(string str)
    {
        Types result;
        if (strInstance.TryGetValue(str, out result))
        {
            return result;
        }
        else
        {
            result = new Types(str);
            return result;
        }

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }

    public static bool operator ==(Types a, Types b)
    {
        return a.value == b.value;
    }
    public static bool operator !=(Types a, Types b)
    {
        return a.value != b.value;
    }

    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";

    #endregion

}

но, конечно, "Типы bob = 4;" было бы бессмысленным, если бы вы не инициализировали их сначала, что бы сорвать точку...

Но в теории TypeA == ТипB будет быстрее...

2

Вот еще один способ выполнить задачу связывания строк с перечислениями:

struct DATABASE {
    public enum enums {NOTCONNECTED, CONNECTED, ERROR}
    static List<string> strings =
        new List<string>() {"Not Connected", "Connected", "Error"};

    public string GetString(DATABASE.enums value) {
        return strings[(int)value];
    }
}

Этот метод называется следующим:

public FormMain() {
    DATABASE dbEnum;

    string enumName = dbEnum.GetString(DATABASE.enums.NOTCONNECTED);
}

Вы можете группировать связанные перечисления в своей собственной структуре. Поскольку этот метод использует тип перечисления, вы можете использовать Intellisense для отображения списка перечислений при вызове GetString().

Вы можете по желанию использовать новый оператор в структуре DATABASE. Не используя его, строки List не выделяются до тех пор, пока не будет выполнен первый вызов GetString().

1

Когда я в такой ситуации, я предлагаю решение ниже.

И как потребительский класс вы могли бы

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyApp.Dictionaries
{
    class Greek
    {

        public static readonly string Alpha = "Alpha";
        public static readonly string Beta = "Beta";
        public static readonly string Gamma = "Gamma";
        public static readonly string Delta = "Delta";


        private static readonly BiDictionary<int, string> Dictionary = new BiDictionary<int, string>();


        static Greek() {
            Dictionary.Add(1, Alpha);
            Dictionary.Add(2, Beta);
            Dictionary.Add(3, Gamma);
            Dictionary.Add(4, Delta);
        }

        public static string getById(int id){
            return Dictionary.GetByFirst(id);
        }

        public static int getByValue(string value)
        {
            return Dictionary.GetBySecond(value);
        }

    }
}

И используя двунаправленный словарь: Исходя из этого (https://stackoverflow.com/questions/255341/getting-key-of-value-of-a-generic-dictionary), предполагая, что ключи будут связаны с одиночными значениями в словаре и похожими на (https://stackoverflow.com/questions/255341/getting-key-of-value-of-a-generic-dictionary), но немного более элегантно. Этот словарь также можно перечислить, и вы можете перемещаться туда и обратно от целых строк. Также вам не нужно иметь строку в вашей кодовой базе, за исключением этого класса.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace MyApp.Dictionaries
{

    class BiDictionary<TFirst, TSecond> : IEnumerable
    {
        IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
        IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

        public void Add(TFirst first, TSecond second)
        {
            firstToSecond.Add(first, second);
            secondToFirst.Add(second, first);
        }

        public TSecond this[TFirst first]
        {
            get { return GetByFirst(first); }
        }

        public TFirst this[TSecond second]
        {
            get { return GetBySecond(second); }
        }

        public TSecond GetByFirst(TFirst first)
        {
            return firstToSecond[first];
        }

        public TFirst GetBySecond(TSecond second)
        {
            return secondToFirst[second];
        }

        public IEnumerator GetEnumerator()
        {
            return GetFirstEnumerator();
        }

        public IEnumerator GetFirstEnumerator()
        {
            return firstToSecond.GetEnumerator();
        }

        public IEnumerator GetSecondEnumerator()
        {
            return secondToFirst.GetEnumerator();
        }
    }
}
1

Хорошо, после прочтения всего вышеизложенного я чувствую, что ребята усложнили проблему преобразования счетчиков в строки. Мне понравилась идея иметь атрибуты по перечислимым полям, но я думаю, что атрибуты в основном используются для метаданных, но в вашем случае я думаю, что все, что вам нужно, это своего рода локализация.

public enum Color 
{ Red = 1, Green = 2, Blue = 3}


public static EnumUtils 
{
   public static string GetEnumResourceString(object enumValue)
    {
        Type enumType = enumValue.GetType();
        string value = Enum.GetName(enumValue.GetType(), enumValue);
        string resourceKey = String.Format("{0}_{1}", enumType.Name, value);
        string result = Resources.Enums.ResourceManager.GetString(resourceKey);
        if (string.IsNullOrEmpty(result))
        {
            result = String.Format("{0}", value);
        }
        return result;
    }
}

Теперь, если мы попытаемся вызвать метод выше, мы можем назвать его таким образом

public void Foo()
{
  var col = Color.Red;
  Console.WriteLine (EnumUtils.GetEnumResourceString (col));
}

Все, что вам нужно сделать, это просто создать файл ресурсов, содержащий все значения перечислителя и соответствующие строки

Resource Name          Resource Value
Color_Red              My String Color in Red
Color_Blue             Blueeey
Color_Green            Hulk Color

На самом деле очень приятно, что это будет очень полезно, если вам нужно, чтобы ваше приложение было локализовано, поскольку все, что вам нужно сделать, это просто создать другой файл ресурсов с новым языком! и Voe-la!

1

на основе MSDN: http://msdn.microsoft.com/en-us/library/cc138362.aspx

foreach (string str in Enum.GetNames(typeof(enumHeaderField)))
{
    Debug.WriteLine(str);
}

str будут именами полей

  • 2
    это даст имя перечисления, вы также можете использовать ToString () для этого, это не то, что было задано. Проверьте msdn.microsoft.com/en-us/library/system.enum.getname.aspx для получения дополнительной информации о вашем bubu
0

Для больших наборов перечислений строк перечисленные примеры могут стать утомительными. Если вам нужен список кодов состояния или список других перечислений на основе строк, система атрибутов раздражает, и статический класс с экземплярами сам по себе раздражает настройку. Для моего собственного решения я использую шаблоны T4, чтобы упростить пересылку с поддержкой строки. Результат получается аналогично тому, как работает класс HttpMethod.

Вы можете использовать его следующим образом:

    string statusCode = ResponseStatusCode.SUCCESS; // Automatically converts to string when needed
    ResponseStatusCode codeByValueOf = ResponseStatusCode.ValueOf(statusCode); // Returns null if not found

    // Implements TypeConverter so you can use it with string conversion methods.
    var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(ResponseStatusCode));
    ResponseStatusCode code = (ResponseStatusCode) converter.ConvertFromInvariantString(statusCode);

    // You can get a full list of the values
    bool canIterateOverValues = ResponseStatusCode.Values.Any(); 

    // Comparisons are by value of the "Name" property. Not by memory pointer location.
    bool implementsByValueEqualsEqualsOperator = "SUCCESS" == ResponseStatusCode.SUCCESS; 

Вы начинаете с файла Enum.tt.

<#@ include file="StringEnum.ttinclude" #>


<#+
public static class Configuration
{
    public static readonly string Namespace = "YourName.Space";
    public static readonly string EnumName = "ResponseStatusCode";
    public static readonly bool IncludeComments = true;

    public static readonly object Nodes = new
    {
        SUCCESS = "The response was successful.",
        NON_SUCCESS = "The request was not successful.",
        RESOURCE_IS_DISCONTINUED = "The resource requested has been discontinued and can no longer be accessed."
    };
}
#>

Затем вы добавляете в свой файл StringEnum.ttinclude.

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#@ CleanupBehavior processor="T4VSHost" CleanupAfterProcessingtemplate="true" #>

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;

namespace <#= Configuration.Namespace #>
{
    /// <summary>
    /// TypeConverter implementations allow you to use features like string.ToNullable(T).
    /// </summary>
    public class <#= Configuration.EnumName #>TypeConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            var casted = value as string;

            if (casted != null)
            {
                var result = <#= Configuration.EnumName #>.ValueOf(casted);
                if (result != null)
                {
                    return result;
                }
            }

            return base.ConvertFrom(context, culture, value);
        }

        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            var casted = value as <#= Configuration.EnumName #>;
            if (casted != null && destinationType == typeof(string))
            {
                return casted.ToString();
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    [TypeConverter(typeof(<#= Configuration.EnumName #>TypeConverter))]
    public class <#= Configuration.EnumName #> : IEquatable<<#= Configuration.EnumName #>>
    {
//---------------------------------------------------------------------------------------------------
// V A L U E S _ L I S T
//---------------------------------------------------------------------------------------------------
<# Write(Helpers.PrintEnumProperties(Configuration.Nodes)); #>

        private static List<<#= Configuration.EnumName #>> _list { get; set; } = null;
        public static List<<#= Configuration.EnumName #>> ToList()
        {
            if (_list == null)
            {
                _list = typeof(<#= Configuration.EnumName #>).GetFields().Where(x => x.IsStatic && x.IsPublic && x.FieldType == typeof(<#= Configuration.EnumName #>))
                    .Select(x => x.GetValue(null)).OfType<<#= Configuration.EnumName #>>().ToList();
            }

            return _list;
        }

        public static List<<#= Configuration.EnumName #>> Values()
        {
            return ToList();
        }

        /// <summary>
        /// Returns the enum value based on the matching Name of the enum. Case-insensitive search.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static <#= Configuration.EnumName #> ValueOf(string key)
        {
            return ToList().FirstOrDefault(x => string.Compare(x.Name, key, true) == 0);
        }


//---------------------------------------------------------------------------------------------------
// I N S T A N C E _ D E F I N I T I O N
//---------------------------------------------------------------------------------------------------      
        public string Name { get; private set; }
        public string Description { get; private set; }
        public override string ToString() { return this.Name; }

        /// <summary>
        /// Implcitly converts to string.
        /// </summary>
        /// <param name="d"></param>
        public static implicit operator string(<#= Configuration.EnumName #> d)
        {
            return d.ToString();
        }

        /// <summary>
        /// Compares based on the == method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(<#= Configuration.EnumName #> a, <#= Configuration.EnumName #> b)
        {
            return !(a == b);
        }

        /// <summary>
        /// Compares based on the .Equals method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(<#= Configuration.EnumName #> a, <#= Configuration.EnumName #> b)
        {
            return a?.ToString() == b?.ToString();
        }

        /// <summary>
        /// Compares based on the .ToString() method
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public override bool Equals(object o)
        {
            return this.ToString() == o?.ToString();
        }

        /// <summary>
        /// Compares based on the .ToString() method
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool Equals(<#= Configuration.EnumName #> other)
        {
            return this.ToString() == other?.ToString();
        }

        /// <summary>
        /// Compares based on the .Name property
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.Name.GetHashCode();
        }
    }
}

<#+

public static class Helpers
{
        public static string PrintEnumProperties(object nodes)
        {
            string o = "";
            Type nodesTp = Configuration.Nodes.GetType();
            PropertyInfo[] props = nodesTp.GetProperties().OrderBy(p => p.Name).ToArray();

            for(int i = 0; i < props.Length; i++)
            {
                var prop = props[i];
                if (Configuration.IncludeComments)
                {
                    o += "\r\n\r\n";
                    o += "\r\n        ///<summary>";
                    o += "\r\n        /// "+Helpers.PrintPropertyValue(prop, Configuration.Nodes);
                    o += "\r\n        ///</summary>";
                }

                o += "\r\n        public static readonly "+Configuration.EnumName+" "+prop.Name+ " = new "+Configuration.EnumName+"(){ Name = \""+prop.Name+"\", Description = "+Helpers.PrintPropertyValue(prop, Configuration.Nodes)+ "};";
            }

            o += "\r\n\r\n";

            return o;
        }

        private static Dictionary<string, string> GetValuesMap()
        {
            Type nodesTp = Configuration.Nodes.GetType();
            PropertyInfo[] props= nodesTp.GetProperties();
            var dic = new Dictionary<string,string>();
            for(int i = 0; i < props.Length; i++)
            {
                var prop = nodesTp.GetProperties()[i];
                dic[prop.Name] = prop.GetValue(Configuration.Nodes).ToString();
            }
            return dic;
        }

        public static string PrintMasterValuesMap(object nodes)
        {
            Type nodesTp = Configuration.Nodes.GetType();
            PropertyInfo[] props= nodesTp.GetProperties();
            string o = "        private static readonly Dictionary<string, string> ValuesMap = new Dictionary<string, string>()\r\n        {";
            for(int i = 0; i < props.Length; i++)
            {
                var prop = nodesTp.GetProperties()[i];
                o += "\r\n            { \""+prop.Name+"\", "+(Helpers.PrintPropertyValue(prop,Configuration.Nodes)+" },");
            }
            o += ("\r\n        };\r\n");

            return o;
        }


        public static string PrintPropertyValue(PropertyInfo prop, object objInstance)
        {
            switch(prop.PropertyType.ToString()){
                case "System.Double":
                    return prop.GetValue(objInstance).ToString()+"D";
                case "System.Float":
                    return prop.GetValue(objInstance).ToString()+"F";
                case "System.Decimal":
                    return prop.GetValue(objInstance).ToString()+"M";
                case "System.Long":
                    return prop.GetValue(objInstance).ToString()+"L";
                case "System.Boolean":
                case "System.Int16":
                case "System.Int32":
                    return prop.GetValue(objInstance).ToString().ToLowerInvariant();
                case "System.String":
                    return "\""+prop.GetValue(objInstance)+"\"";
            }

            return prop.GetValue(objInstance).ToString();
        }

        public static string _ (int numSpaces)
        {
            string o = "";
            for(int i = 0; i < numSpaces; i++){
                o += " ";
            }

            return o;
        }
}
#>

Наконец, вы перекомпилируете свой файл Enum.tt, и результат выглядит следующим образом:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Linq;
using System.Collections.Generic;

namespace YourName.Space
{
    public class ResponseStatusCode
    {
//---------------------------------------------------------------------------------------------------
// V A L U E S _ L I S T 
//---------------------------------------------------------------------------------------------------



        ///<summary>
        /// "The response was successful."
        ///</summary>
        public static readonly ResponseStatusCode SUCCESS = new ResponseStatusCode(){ Name = "SUCCESS", Description = "The response was successful."};


        ///<summary>
        /// "The request was not successful."
        ///</summary>
        public static readonly ResponseStatusCode NON_SUCCESS = new ResponseStatusCode(){ Name = "NON_SUCCESS", Description = "The request was not successful."};


        ///<summary>
        /// "The resource requested has been discontinued and can no longer be accessed."
        ///</summary>
        public static readonly ResponseStatusCode RESOURCE_IS_DISCONTINUED = new ResponseStatusCode(){ Name = "RESOURCE_IS_DISCONTINUED", Description = "The resource requested has been discontinued and can no longer be accessed."};


        private static List<ResponseStatusCode> _list { get; set; } = null;
        public static List<ResponseStatusCode> ToList()
        {
            if (_list == null)
            {
                _list = typeof(ResponseStatusCode).GetFields().Where(x => x.IsStatic && x.IsPublic && x.FieldType == typeof(ResponseStatusCode))
                    .Select(x => x.GetValue(null)).OfType<ResponseStatusCode>().ToList();
            }

            return _list;
        }

        public static List<ResponseStatusCode> Values()
        {
            return ToList();
        }

        /// <summary>
        /// Returns the enum value based on the matching Name of the enum. Case-insensitive search.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static ResponseStatusCode ValueOf(string key)
        {
            return ToList().FirstOrDefault(x => string.Compare(x.Name, key, true) == 0);
        }


//---------------------------------------------------------------------------------------------------
// I N S T A N C E _ D E F I N I T I O N 
//---------------------------------------------------------------------------------------------------       
        public string Name { get; set; }
        public string Description { get; set; }
        public override string ToString() { return this.Name; }

        /// <summary>
        /// Implcitly converts to string.
        /// </summary>
        /// <param name="d"></param>
        public static implicit operator string(ResponseStatusCode d)
        {
            return d.ToString();
        }

        /// <summary>
        /// Compares based on the == method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(ResponseStatusCode a, ResponseStatusCode b)
        {
            return !(a == b);
        }

        /// <summary>
        /// Compares based on the .Equals method. Handles nulls gracefully.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(ResponseStatusCode a, ResponseStatusCode b)
        {
            return a?.ToString() == b?.ToString();
        }

        /// <summary>
        /// Compares based on the .ToString() method
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public override bool Equals(object o)
        {
            return this.ToString() == o?.ToString();
        }

        /// <summary>
        /// Compares based on the .Name property
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.Name.GetHashCode();
        }
    }
}
0

Я хорошо знаю, что на этот вопрос уже был дан ответ, и что OP уже удовлетворен принятым ответом. Но я нашел большинство ответов, в том числе принятых, немного сложнее.

У меня есть проект, который дал мне такую ​​ситуацию, и я смог добиться этого таким образом.

Во-первых, вы должны рассмотреть оболочку имен перечислений:

public enum AuthenticationMethod
{
    Forms = 1,
    WindowsAuthentication = 2,
    SingleSignOn = 3
}

Тогда получим это расширение:

using System.Text.RegularExpression;

public static class AnExtension
{
    public static string Name(this Enum value)
    {
        string strVal = value.ToString();
        try
        {
            return Regex.Replace(strVal, "([a-z])([A-Z])", "$1 $2");
        }
        catch
        {
        }
        return strVal;
    }
}

Через это вы можете превратить каждое имя enum в его строковое представление с каждым словом, разделенным пробелом. Пример:

AuthenticationMethod am = AuthenticationMethod.WindowsAuthentication;
MessageBox.Show(am.Name());
  • 0
    Если вы читаете оригинальный вопрос, он хочет, чтобы другое сопоставление, такое как SingleSignOn стало SSO . Ваше решение не работает.
0

Я с Харви, но не использую const. Я могу смешивать и сопоставлять строку, int, что угодно.

public class xlsLayout
{
    public int xlHeaderRow = 1;
    public int xlFirstDataRow = 2;
    public int xlSkipLinesBetweenFiles = 1; //so 0 would mean don't skip
    public string xlFileColumn = "A";
    public string xlFieldColumn = "B";
    public string xlFreindlyNameColumn = "C";
    public string xlHelpTextColumn = "D";
}

Затем позже...

public partial class Form1 : Form
{
    xlsLayout xlLayout = new xlsLayout();

    xl.SetCell(xlLayout.xlFileColumn, xlLayout.xlHeaderRow, "File Name");
    xl.SetCell(xlLayout.xlFieldColumn, xlLayout.xlHeaderRow, "Code field name");
    xl.SetCell(xlLayout.xlFreindlyNameColumn, xlLayout.xlHeaderRow, "Freindly name");
    xl.SetCell(xlLayout.xlHelpTextColumn, xlLayout.xlHeaderRow, "Inline Help Text");
}
  • 0
    Я также использую Harvey's, но я использую модификатор доступа const , потому что это значение времени компиляции, и поэтому я могу использовать их в выражениях switch . Использование вашего кода может работать в определенных ситуациях, но вы не можете использовать свои значения в switch .
0

Мой ответ, работающий над ответом @user29964 (который, безусловно, самый простой и ближайший к Enum),

 public class StringValue : System.Attribute
    {
        private string _value;

        public StringValue(string value)
        {
            _value = value;
        }

        public string Value
        {
            get { return _value; }
        }



        public static string GetStringValue(Enum Flagvalue)
        {
            Type type = Flagvalue.GetType();
            string[] flags = Flagvalue.ToString().Split(',').Select(x => x.Trim()).ToArray();
            List<string> values = new List<string>();

            for (int i = 0; i < flags.Length; i++)
            {

                FieldInfo fi = type.GetField(flags[i].ToString());

                StringValue[] attrs =
                   fi.GetCustomAttributes(typeof(StringValue),
                                           false) as StringValue[];
                if (attrs.Length > 0)
                {
                    values.Add(attrs[0].Value);
                }
            }
            return String.Join(",", values);

        }

Использование

[Flags]
    public enum CompeteMetric
    {

        /// <summary>
        /// u
        /// </summary>
        [StringValue("u")]//Json mapping
        Basic_UniqueVisitors = 1 //Basic
             ,
        /// <summary>
        /// vi
        /// </summary>
        [StringValue("vi")]//json mapping
        Basic_Visits = 2// Basic
            ,
        /// <summary>
        /// rank
        /// </summary>
        [StringValue("rank")]//json mapping
        Basic_Rank = 4//Basic
 }

Пример

        CompeteMetric metrics = CompeteMetric.Basic_Visits | CompeteMetric.Basic_Rank;
        string strmetrics = StringValue.GetStringValue(metrics);

это вернет "VI, звание"

0

Подход, который я нашел для интернационализации Enums или получения текста Enums из соответствующих файлов ресурсов, заключается в создании класса атрибута путем наследования класса DescriptionAttribute

public class EnumResourceAttribute : DescriptionAttribute
{

    public Type ResourceType { get; private set; }
    public string ResourceName { get; private set; }
    public int SortOrder { get; private set; }
    public EnumResourceAttribute(Type ResourceType,
                         string ResourceName,
                         int SortOrder)
    {

        this.ResourceType = ResourceType;
        this.ResourceName = ResourceName;
        this.SortOrder = SortOrder;
    }
}

Создайте еще один класс Static, который предоставит методы расширения для GetString и GetStrings.

public static class EnumHelper
{
    public static string GetString(this Enum value)
    {
        EnumResourceAttribute ea =
       (EnumResourceAttribute)value.GetType().GetField(value.ToString())
        .GetCustomAttributes(typeof(EnumResourceAttribute), false)
         .FirstOrDefault();
        if (ea != null)
        {
            PropertyInfo pi = ea.ResourceType
             .GetProperty(CommonConstants.ResourceManager);
            if (pi != null)
            {
                ResourceManager rm = (ResourceManager)pi
                .GetValue(null, null);
                return rm.GetString(ea.ResourceName);
            }

        }
        return string.Empty;
    }


    public static IList GetStrings(this Type enumType)
    {
        List<string> stringList = new List<string>();
        FieldInfo[] fiArray = enumType.GetFields();
        foreach (FieldInfo fi in fiArray)
        {
            EnumResourceAttribute ea =
                (EnumResourceAttribute)fi
                     .GetCustomAttributes(typeof(EnumResourceAttribute), false)
                     .FirstOrDefault();
            if (ea != null)
            {
                PropertyInfo pi = ea.ResourceType
                                    .GetProperty(CommonConstants.ResourceManager);
                if (pi != null)
                {
                    ResourceManager rm = (ResourceManager)pi
                                          .GetValue(null, null);
                    stringList.Add(rm.GetString(ea.ResourceName));
                }
            }
        }
        return stringList.ToList();
    }
}

А на элементах вашего Enum вы можете написать:

public enum Priority
{
     [EnumResourceAttribute(typeof(Resources.AdviceModule), Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberHigh, 1)]
    High,
     [EnumResourceAttribute(typeof(Resources.AdviceModule), Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberRoutine, 2)]
    Routine
}

Где Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberHigh и Resources.ResourceNames.AdviceCreateAdviceExternaPriorityMemberRoutine являются константами в файле ресурсов или вы можете сказать строки, значения которых могут быть доступны в разных культурах.

Если вы реализуете свое веб-приложение в архитектуре MVC, создайте свойство

private IList result;
public IList Result
{
    get
    {
        result = typeof(Priority).GetStrings();
        return result;
    }
}

а в вашем файле .cshtml вы можете просто привязать перечисление к выпадающему списку, например:

@Html.DropDownListFor(model => Model.vwClinicalInfo.Priority, new SelectList(Model.Result))

Спасибо Ratnesh

0

Использовать объект Enum.Parse(System.Type enumType, строковое значение, bool ignoreCase); получил http://blogs.msdn.com/b/tims/archive/2004/04/02/106310.aspx

  • 5
    Вы должны пересмотреть этот ответ, чтобы включить пример, а не просто ссылку.
  • 0
    и прочитайте вопрос, ответ тот же, что и выше msdn.microsoft.com/en-us/library/system.enum.getname.aspx

Ещё вопросы

Сообщество Overcoder
Наверх
Меню