более элегантный дизайн о enum - PullRequest
7 голосов
/ 26 июля 2011

Я учусь на C #.

Я слышал, C # - один из самых конструктивных языков. ребята, не могли бы вы сделать мой код более элегантным и эффективным?

public class ISO639
{
    public enum ISO639Code
    {
        Afrikaans,                      //af
        Albanian,                       //sq
        Amharic,                        //am

        ...

        Yiddish,                        //yi
        Unknown                         
    }


    public static string GetISO639CodeString(ISO639.ISO639Code l)
    {
        switch (l)
        {
            case ISO639Code.English: return "en";
            case ISO639Code.Japanese: return "ja";

            ...

            case ISO639Code.Hebrew: return "he";
            default: return "";
        }


    public static ISO639.ISO639Code GetISO39CodeValue(string s)
    {

        switch (s)
        {
            case "ko" : return ISO639Code.Korean;
            case "en" : return ISO639Code.English;

            ...

            case "hu" : return ISO639Code.Hungarian;
            default: return ISO639Code.Unknown;
        }
    }
}

Вот мой класс ISO639. Этот класс обеспечивает перечисление для кода ISO639, но мне нужно преобразование типа из перечисления ISO639 в обычную строку. (например, ISO639.ISO639Code.Italian => "it"). Мне также нужно преобразование типа из простой строки в перечисление ISO639. (напр. "it" => ISO639.ISO639Code.Italian).

Есть ли для этого более эффективный стиль кодирования?

Ответы [ 9 ]

9 голосов
/ 26 июля 2011

Вы можете добавить стандартный System.ComponentModel.Description к каждой записи перечисления и затем прочитать его.

public enum ISO639Code       
{ 
  [Description("af")]
  Afrikaans
}

public static class EnumExtensions
{
    // Extension method to read Description value
    public static string GetDescription(this Enum currentEnum)
    {
         var fi = currentEnum.GetType().GetField(currentEnum.ToString()); 
         var da = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)); 
         return da != null ? da.Description : currentEnum.ToString();
     } 
}

// **How-to read it**
ISO639Code isoCode = ISO639Code.Afrikaans;

// this will returns "af"
string isoDescription = isoCode.GetDescription(); 

РЕДАКТИРОВАТЬ:

    string searchFor = "af"; 
    ISO639Code foundEntry;

    // Loop through all entries descriptions       
    var allEntries = Enum.GetValues(typeof(ISO639Code));
    foreach (var entry in allEntries)
    {
        // If you will extract this as separate method and use it for search not only loop
        // through the all entries - you can put here is yield return description
        var currentEntry = ((ISO639Code)entry);
        string description = currentEntry.GetDescription();
        if (description == searchFor)
        {
            foundEntry = currentEntry;
            break;
        }
    }
8 голосов
/ 26 июля 2011

Конечно. Вы можете использовать атрибуты :

public enum ISO639Code
{
    [CodeString("af")] Afrikaans,
    [CodeString("sq")] Albanian,    
}
2 голосов
/ 26 июля 2011

Используйте словарь, например: new Dictionary<ISO639Code, string>.

2 голосов
/ 26 июля 2011

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

Например, см. http://pietschsoft.com/post/2008/07/c-enhance-enums-using-extension-methods.aspx

1 голос
/ 26 июля 2011

Я бы просто сохранил информацию в словарном объекте.Таким образом, вы можете ссылаться на имя по ключу и получить значение напрямую.

0 голосов
/ 26 июля 2011

Я бы выбрал ISO639Code в качестве класса вместо enum:

public class ISO639Code
{
    public string Value { get; set ; }
    public string Code { get; set; }

    public ISO639Code()
    {
        this.Value = "";
        this.Code = "";
    }

    public ISO639Code(string value, string code)
        : this()
    {
        this.Value = value;
        this.Code = code;
    }

    public override bool Equals(object obj)
    {
        if (obj != null)
        {
            if (obj is string)
                return obj.ToString().Equals(this.Value, StringComparison.CurrentCultureIgnoreCase);
            if (obj is ISO639Code)
                return ((ISO639Code)obj).Value.Equals(this.Value, StringComparison.CurrentCultureIgnoreCase);
        }
        return false;
    }

    public override int GetHashCode()
    {
        return this.Value.GetHashCode();
    }

    public override string ToString()
    {
        return this.Value;
    }
}

Тогда получим глобальное List<ISO639Code> со всеми возможными кодами и для поиска конкретного кода на основе имени или значения кода, простоИщите это в Списке.

Лично я предпочитаю это, чем настраивать перечисление.

0 голосов
/ 26 июля 2011

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

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

    общедоступные перечисления IsoCodes { [Описание ( "AF")] Африканцы = 0, [Описание ( "Я")] Американцы = 1 }

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

public static string GetDescription(this Enum value)
        {
            var entries = value.ToString().Split(FlagEnumSeparatorCharacter);

            var description = new string[entries.Length];

            for (var i = 0; i < entries.Length; i++)
            {
                var fieldInfo = value.GetType().GetField(entries[i].Trim());
                var attributes = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];
                description[i] = (attributes.Length > 0) ? attributes[0].Description : entries[i].Trim();
            }

            return String.Join(", ", description);
        }

public static int GetValue(this Enum value)
    {
        return (int)value.GetType().GetField(value.ToString()).GetRawConstantValue();
    }

    public static T ToEnum<T>(this string value)
    {
        if (typeof(T).BaseType.Name != typeof(Enum).Name)
        {
            throw new Exception("Not an enum");
        }
        return (T)Enum.Parse(typeof(T), value, true);
    }

    public static T ToEnum<T>(this int value)
    {
        if (typeof(T).BaseType.Name != typeof(Enum).Name)
        {
            throw new Exception("Not an enum");
        }
        return (T)Enum.ToObject(typeof(T), value);
    }

Теперь используйте ваши перечисления как хотите.

0 голосов
/ 26 июля 2011

Посмотрите на пространство имен System.Globailization.Требуемая функциональность выглядит уже реализованной там.В худшем случае вы можете увидеть архитектуру и технику, примененную в .Net framework для решения очень похожей проблемы.

0 голосов
/ 26 июля 2011

У вас есть перечисление:

 public enum ISO639Code
 {
    Afrikaans = 1,                      
    Albanian  = 2,                       
    Amharic   = 3, 

и т. Д.

Создайте таблицу базы данных:

 ISO639Id   int   PK,
 ISO639Code char(2)

Где ISO639Id соответствует значению перечисления.

В коде вы хотите, чтобы класс ISO630 содержал значения Id и Code, считанные из базы данных.(Вы можете загрузить его один раз, а затем кэшировать в памяти.)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...