Перечисления со строковыми значениями и поиск перечисления по значению - PullRequest
7 голосов
/ 17 августа 2010

Я хочу иметь перечисление, подобное следующему, а затем иметь метод, похожий на Util.FindFruitByValue ("A"), который возвращает перечисление Apple.это потому, что сокращения хранятся в базе данных, и мне нужно преобразовать их в соответствующие перечисления после чтения из базы данных.возможно ли это ИЛИ мне нужно создать отдельный класс для него?Пожалуйста, дайте мне знать.Заранее спасибо.

public enum Fruit
{
    Apple = "A"
    Banana = "B"
    Cherry = "C"
}

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

Ответы [ 7 ]

20 голосов
/ 17 августа 2010

Я решил проблему с помощью атрибута Description в enum. Решение заключается в следующем. Я использую метод расширения, чтобы получить описание. код для получения описания взят по этой ссылке http://blog.spontaneouspublicity.com/post/2008/01/17/Associating-Strings-with-enums-in-C.aspx. спасибо за ваши ответы.

    public enum Fruit
{
    [Description("Apple")]
    A,
    [Description("Banana")]
    B,
    [Description("Cherry")]
    C
}

public static class Util
{
    public static T StringToEnum<T>(string name)
    {
        return (T)Enum.Parse(typeof(T), name);
    }

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

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

        if (attributes != null &&
            attributes.Length > 0)
            return attributes[0].Description;
        else
            return value.ToString();
    }
}
12 голосов
/ 17 августа 2010

Вы можете поместить значения в Dictionary для их эффективного поиска:

Dictionary<string, Fruit> fruitValues = new Dictionary<string, Fruit>();
fruitValues.Add("A", Fruit.Apple);
fruitValues.Add("B", Fruit.Banana);
fruitValues.Add("C", Fruit.Cherry);

Lookup:

string dataName = "A";
Fruit f = fruitValues[dataName];

Если значение может отсутствовать:

string dataName = "A";
Fruit f;
if (fruitValues.TryGetValue(dataName, out f)) {
  // got the value
} else {
  // there is no value for that string
}
2 голосов
/ 13 июля 2014

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

Библиотека называется EnumStringValues ​​и доступна из nuget в VS (страница пакета также находится здесь: https://www.nuget.org/packages/EnumStringValues) SourceCode находится на GitHub здесь: https://github.com/Brondahl/EnumStringValues

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

1 голос
/ 17 августа 2010

Извините, я упустил определение Enum ОП. Очевидно, что значения Enum должны быть числовым типом, поэтому определение OP не будет работать.

Одна мысль, которую я имел, состояла в том, чтобы использовать значение char в качестве значения Enum, например

public enum Fruit
{
    Apple  = 65, //"A",
    Banana = 66, // "B",
    Cherry = 67 //"C"
}

Согласно Convert.ToInt32 ('A') - не уверен, что здесь делать с чувствительностью к регистру. Затем, возьмите правильный результат путем наложения. Я все еще играю с примером, рад услышать некоторые предложения.

ОК, извините за задержку. Вот еще немного об этом:

public static class EnumConverter<T>
{
    public static T ToEnum(char charToConvert, out bool success)
    {
        try
        {                
            int intValue = Convert.ToInt32(charToConvert);                
            if (Enum.IsDefined(typeof(T), intValue))
            {
                success = true;
                return (T)Enum.ToObject(typeof(T), intValue);
            }
       }
       catch (ArgumentException ex)
       {
               // Use your own Exception Management Here
       }
       catch (InvalidCastException ex)
       {
           // Use your own Exception Management Here
       }
       success = false;
       return default(T);
    }
}

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

bool success = false;
Fruit selected = EnumConverter<Fruit>.ToEnum('A', out success);
if (success)
{
   // go for broke
}
1 голос
/ 17 августа 2010

Как насчет использования Hashtable?

0 голосов
/ 15 января 2014

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

Вы можете использовать шаблон типа enum типа safe, как в этом посте, описанном:

https://stackoverflow.com/a/424414/1257584

0 голосов
/ 12 ноября 2012

Я создал небольшой класс DynamicEnum, который позволяет очень легко извлекать перечисления как из домена, так и из хранилища данных.

public abstract class DynamicEnum<T> : IEquatable<T>, IComparable<T>
    where T : DynamicEnum<T>, new()
{
    #region Instance

    public int PathCode { get; private set; }
    public string PathValue { get; private set; }

    protected DynamicEnum() { }

    protected DynamicEnum(int pathCode, string pathValue)
    {
        PathCode = pathCode;
        PathValue = PathValue;
    }

    #region IEquatable<AreaStatus> Members

    public bool Equals(T other)
    {
        return PathCode == other.PathCode;
    }

    #endregion

    public override bool Equals(object obj)
    {
        return Equals(obj as T);
    }

    public override int GetHashCode()
    {
        return PathCode.GetHashCode();
    }

    #region IComparable<AreaStatus> Members

    public int CompareTo(T other)
    {
        return PathCode.CompareTo(other.PathCode);
    }

    #endregion

    #endregion

    #region Class / Static

    static DynamicEnum()
    {
        // Despite appearances, static methods are not really inherited by
        // child classes. This means when the mapping fields below are accessed
        // by an implementing class the CLR does not see it as a method on that
        // class. In the event that the implementing class's static constructor
        // hasn't been called yet, it will not be called at that point since
        // technically no static method/property or instance of the implementing
        // class has been used. Working around this by creating an instance here
        // which causes the derived class's static constructor to be called
        // beforehand. This could alternately be solved by moving the default 'enum'
        // value initialization out of the implementing classes to the Global.asax 
        // where the database 'enum' values are optionally loaded.
        new T();
    }

    public static void Initialize(IEnumerable<T> statuses)
    {
        IntoDomainMapping = statuses.ToDictionary(x => x.PathValue, x => x);
        IntoDBMapping = IntoDomainMapping.ToDictionary(x => x.Value, x => x.Key);
    }

    public static Dictionary<string, T> IntoDomainMapping { get; protected set; }
    public static Dictionary<T, string> IntoDBMapping { get; protected set; }

    #endregion

    #region Operator Overloads

    public static bool operator ==(DynamicEnum<T> s1, T s2)
    {
        return s1.Equals(s2);
    }

    public static bool operator !=(DynamicEnum<T> s1, T s2)
    {
        return !s1.Equals(s2);
    }

    public static bool operator >(DynamicEnum<T> s1, T s2)
    {
        return s1.CompareTo(s2) > 0;
    }

    public static bool operator <(DynamicEnum<T> s1, T s2)
    {
        return s1.CompareTo(s2) < 0;
    }

    public static bool operator >=(DynamicEnum<T> s1, T s2)
    {
        return s1.CompareTo(s2) >= 0;
    }

    public static bool operator <=(DynamicEnum<T> s1, T s2)
    {
        return s1.CompareTo(s2) <= 0;
    }

    #endregion
}

Вот класс "Enum"

    public class ResourcePath : DynamicEnum<ResourcePath>
{
    public ResourcePath() { }

    public ResourcePath(int pathCode, string pathValue) 
        : base(pathCode, pathValue) { }


    static ResourcePath()
    {
        Initialize(new List<ResourcePath>
            {
                new ResourcePath(1, "customer.list"),
                new ResourcePath(1, "customer.create"),
                new ResourcePath(1, "customer.info"),
                new ResourcePath(1, "customer.update"),
                new ResourcePath(1, "customer.delete"),
            });
    }

    public static ResourcePath Deleted
    { 
        get { return ResourcePath.IntoDomainMapping["DE"]};
    }
}

Наконец, основное использование

var resource = GetAllResources().Where(e => e.PathCode == pathCode).firstOrDefault();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...