Связывание перечислений со строками в C # - PullRequest
264 голосов
/ 10 марта 2009

Я знаю, что следующее невозможно, потому что оно должно быть int

enum GroupTypes
{
    TheGroup = "OEM",
    TheOtherGroup = "CMB"
}

Из моей базы данных я получаю поле с непонятными кодами (OEM и CMB). Я хотел бы превратить это поле в перечисление или что-то еще понятное. Поскольку целью является удобочитаемость, решение должно быть кратким.
Какие еще варианты у меня есть?

Ответы [ 28 ]

3 голосов
/ 05 марта 2014

C # не поддерживает перечисляемые строки, но в большинстве случаев вы можете использовать список или словарь, чтобы получить желаемый эффект.

например. Чтобы распечатать результаты «пройдено / не пройдено»:

List<string> PassFail = new List<string> { "FAIL", "PASS" };
bool result = true;
Console.WriteLine("Test1: " + PassFail[result.GetHashCode()]);
3 голосов
/ 10 марта 2009

Рассматривали ли вы таблицу поиска с использованием словаря?

enum GroupTypes
{
    TheGroup,
    TheOtherGroup
}

Dictionary<string, GroupTypes> GroupTypeLookup = new Dictionary<string, GroupTypes>();
// initialize lookup table:
GroupTypeLookup.Add("OEM", TheGroup);
GroupTypeLookup.Add("CMB", TheOtherGroup);

Затем вы можете использовать GroupTypeLookup.TryGetValue () для поиска строки при ее чтении.

2 голосов
/ 10 марта 2009

Мой первый вопрос - есть ли у вас доступ к самой базе данных? Это должно быть нормализовано в базе данных, в идеале, в противном случае любое решение будет подвержено ошибкам. По моему опыту, поля данных, заполненные "OEM" и "CMB", имеют тенденцию к тому, что со временем будут смешиваться такие вещи, как "oem" и другие "данные дерьма". в таблице, содержащей элементы, такие как Enum, и все готово, с гораздо более чистой структурой.

Если этого нет, я бы сделал ваш Enum и создал бы класс, чтобы разобрать вашу строку в Enum для вас. Это, по крайней мере, даст вам некоторую гибкость в обработке нестандартных записей и гораздо большую гибкость для перехвата или обработки ошибок, чем любое из обходных путей с использованием Enum.Parse / Reflection / и т.д. Словарь будет работать, но может сломаться, если у вас возникнут проблемы с регистром и т. Д.

Я бы порекомендовал написать класс, чтобы вы могли сделать:

// I renamed this to GroupType, since it sounds like each element has a single type...
GroupType theType = GroupTypeParser.GetGroupType(theDBString);

Это сохраняет большую часть вашей читабельности без необходимости изменения БД.

2 голосов
/ 10 марта 2009

Я бы сделал это в классе, чтобы избежать перечисления вообще. И затем с использованием обработчика типов вы можете создать объект, когда вы берете его из базы данных.

IE:

public class Group
{
    public string Value{ get; set; }
    public Group( string value ){ Value = value; } 
    public static Group TheGroup() { return new Group("OEM"); }
    public static Group OtherGroup() { return new Group("CMB"); }

}
2 голосов
/ 20 ноября 2014

Если я правильно понимаю, вам нужно преобразование из строки в enum:

enum GroupTypes {
    Unknown = 0,
    OEM = 1,
    CMB = 2
}
static GroupTypes StrToEnum(string str){
    GroupTypes g = GroupTypes.Unknown;
    try {
        object o = Enum.Parse(typeof(GroupTypes), str, true);
        g = (GroupTypes)(o ?? 0);
    } catch {
    }
    return g;
}
// then use it like this
GroupTypes g1 = StrToEnum("OEM");
GroupTypes g2 = StrToEnum("bad value");

Если хотите, вы можете сделать его более универсальным с помощью обобщений для типа enum

2 голосов
/ 10 марта 2009

Я бы просто создал словарь и использовал код в качестве ключа.

Редактировать: чтобы ответить на комментарий о обратном поиске (поиске ключа), это было бы не очень эффективно. Если это необходимо, я бы написал новый класс для его обработки.

2 голосов
/ 18 октября 2017

Небольшая настройка метода расширения Glennular, так что вы можете использовать расширение не только для ENUM;

using System;
using System.ComponentModel;
namespace Extensions {
    public static class T_Extensions {
        /// <summary>
        /// Gets the Description Attribute Value
        /// </summary>
        /// <typeparam name="T">Entity Type</typeparam>
        /// <param name="val">Variable</param>
        /// <returns>The value of the Description Attribute or an Empty String</returns>
        public static string Description<T>(this T t) {
            DescriptionAttribute[] attributes = (DescriptionAttribute[])t.GetType().GetField(t.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return attributes.Length > 0 ? attributes[0].Description : string.Empty;
        }
    }
}

Или используя Linq

using System;
using System.ComponentModel;
using System.Linq;

namespace Extensions {


public static class T_Extensions {
        public static string Description<T>(this T t) =>
            ((DescriptionAttribute[])t
            ?.GetType()
            ?.GetField(t?.ToString())
            ?.GetCustomAttributes(typeof(DescriptionAttribute), false))
            ?.Select(a => a?.Description)
            ?.FirstOrDefault() 
            ?? string.Empty;  
    }
}
2 голосов
/ 25 января 2018
public class DataType
{
    private readonly string value;
    private static readonly Dictionary<string, DataType> predefinedValues;

    public static readonly DataType Json = new DataType("json");
    public static readonly DataType Xml = new DataType("xml");
    public static readonly DataType Text = new DataType("text");
    public static readonly DataType Html = new DataType("html");
    public static readonly DataType Binary = new DataType("binary");

    static DataType()
    {
        predefinedValues = new Dictionary<string, DataType>();
        predefinedValues.Add(Json.Value, Json);
        predefinedValues.Add(Xml.Value, Xml);
        predefinedValues.Add(Text.Value, Text);
        predefinedValues.Add(Html.Value, Html);
        predefinedValues.Add(Binary.Value, Binary);
    }

    private DataType(string value)
    {
        this.value = value;
    }

    public static DataType Parse(string value)
    {
        var exception = new FormatException($"Invalid value for type {nameof(DataType)}");
        if (string.IsNullOrEmpty(value))
            throw exception;

        string key = value.ToLower();
        if (!predefinedValues.ContainsKey(key))
            throw exception;

        return predefinedValues[key];
    }

    public string Value
    {
        get { return value; }
    }
}
1 голос
/ 19 января 2018

Я в основном искал ответ Reflection от @ ArthurC

Просто, чтобы немного расширить его ответ, вы можете сделать его еще лучше, используя обобщенную функцию:

    // If you want for a specific Enum
    private static string EnumStringValue(GroupTypes e)
    {
        return EnumStringValue<GroupTypes>(e);
    }

    // Generic
    private static string EnumStringValue<T>(T enumInstance)
    {
        return Enum.GetName(typeof(T), enumInstance);
    } 

Тогда вы можете просто обернуть все, что у вас есть

EnumStringValue(GroupTypes.TheGroup) // if you incorporate the top part

или

EnumStringValue<GroupTypes>(GroupTypes.TheGroup) // if you just use the generic
1 голос
/ 25 апреля 2017

Это способ использования в качестве строго типизированного параметра или в виде строки :

public class ClassLikeEnum
{
    public string Value
    {
        get;
        private set;
    }

    ClassLikeEnum(string value) 
    {
        Value = value;
    }

    public static implicit operator string(ClassLikeEnum c)
    {
        return c.Value;
    }

    public static readonly ClassLikeEnum C1 = new ClassLikeEnum("RandomString1");
    public static readonly ClassLikeEnum C2 = new ClassLikeEnum("RandomString2");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...