开发者

more elegant design about enum

开发者 https://www.devze.com 2023-03-23 12:11 出处:网络
I\'m on learning for C#. I heared C# is one of the most constructible language. so would you guys make my code more elegant and efficient?

I'm on learning for C#.

I heared C# is one of the most constructible language. so would you guys make my code more elegant and efficient?

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

Here is a my class ISO639. This class provides enum for ISO639 code, but I need a type conversion on from ISO639 enum to plain string. (ex. ISO639.ISO639Code.Italian => "it"). I also need a type conversion from plain string to ISO639 enum. (ex. "it" => ISO639.ISO开发者_如何学Go639Code.Italian).

Is there a more efficient coding style for that?


You can add standard System.ComponentModel.Description attribute to each enum entry and then read it.

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

EDIT:

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


Sure. You can use attributes:

public enum ISO639Code
{
    [CodeString("af")] Afrikaans,
    [CodeString("sq")] Albanian,    
}


Use dictionary, for example: new Dictionary<ISO639Code, string>.


I suggest you to use C# extension methods to enums, they allow you to add whatever logic you want.

For example, see http://pietschsoft.com/post/2008/07/c-enhance-enums-using-extension-methods.aspx


I'd simply store the information in a dictionary-like object. This way you can reference the name by key and get the value directly.


You have an enum:

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

etc.

Create a database table:

 ISO639Id   int   PK,
 ISO639Code char(2)

Where the ISO639Id maps to the value of the enum.

In code you'd want a ISO630 Class containing Id and Code values read from the database. (You can load this once and then cache it in memory.)

The beauty of this approach, is it can be easily extended so that if in future you wanted to store more pieces of information for each ISO639 code, you could simply add another field.


Look at System.Globailzation namespace. The functionality you require looks to be already implemented there. At worst you can see the architecture and technique applied in the .Net framework to solve a very similar problem.


Enumerations are really good to work in code, as they are really strongly typed and make refactoring easier. Follow these steps:

  1. Use attributes for whatever extra information you want to attach to an enum. Usually this is a simple Description attribute. Something like:

    public enum IsoCodes { [Description("af")] Africans = 0, [Description("am")] Americans = 1 }

Then write some extension methods to convert strings and integers to and from this enum:

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

Now use your enums as you like.


I would go with having ISO639Code as class instead of 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;
    }
}

Then have global List<ISO639Code> with all possible codes, and to find specific code based on code name or value, just search for this in the List.

Personally, I prefer this over tweaking the enum.

0

精彩评论

暂无评论...
验证码 换一张
取 消