C# 更优雅的enum设计

C# 更优雅的enum设计,c#,enums,C#,Enums,我在为C#学习 我听说C#是最具可构造性的语言之一。你们能让我的代码更加优雅高效吗 public class ISO639 { public enum ISO639Code { Afrikaans, //af Albanian, //sq Amharic, //am ...

我在为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.意大利语)

有更有效的编码方式吗?

当然。您可以使用:

我建议您对枚举使用C#扩展方法,它们允许您添加任何需要的逻辑


例如,请参见

我只需将信息存储在类似字典的对象中。通过这种方式,您可以按键引用名称并直接获取值。

使用字典,例如:
新建字典

您可以将标准属性添加到每个枚举条目中,然后读取它

公共枚举ISO639Code
{ 
[说明(“af”)]
南非荷兰语
}
公共静态类枚举扩展
{
//用于读取描述值的扩展方法
公共静态字符串GetDescription(此枚举currentEnum)
{
var fi=currentEnum.GetType().GetField(currentEnum.ToString());
var da=(DescriptionAttribute)Attribute.GetCustomAttribute(fi,typeof(DescriptionAttribute));
返回da!=null?da.Description:currentEnum.ToString();
} 
}
//**如何阅读**
ISO639Code等代码=ISO639Code.南非荷兰语;
//这将返回“af”
字符串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;
        }
    }
您有一个枚举:

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

创建数据库表:

 ISO639Id   int   PK,
 ISO639Code char(2)
其中ISO639Id映射到枚举的值

在代码中,您需要一个包含从数据库读取的Id和代码值的ISO630类。 (您可以加载一次,然后将其缓存在内存中。)


这种方法的美妙之处在于,它可以很容易地扩展,以便将来如果您想为每个ISO639代码存储更多信息,只需添加另一个字段即可。

查看System.Globalization命名空间。您需要的功能看起来已经在那里实现了。在最坏的情况下,您可以看到在.Net framework中应用的体系结构和技术来解决一个非常类似的问题。

枚举非常适合在代码中工作,因为它们确实是强类型的,并且使重构更容易。 遵循以下步骤:

  • 对要附加到枚举的任何额外信息使用属性。通常这是一个简单的
    描述
    属性。比如:

    公共枚举等参线 { [说明(“af”)] 非洲人=0, [说明(“am”)] 美国人=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);
        }
    
    公共静态字符串GetDescription(此枚举值)
    {
    var entries=value.ToString().Split(flagnumsparatorcharacter);
    变量说明=新字符串[entries.Length];
    对于(var i=0;i0)?属性[0]。description:条目[i]。Trim();
    }
    返回字符串。Join(“,”,description);
    }
    公共静态int GetValue(此枚举值)
    {
    返回(int)value.GetType().GetField(value.ToString()).GetRawConstantValue();
    }
    公共静态T ToEnum(此字符串值)
    {
    if(typeof(T).BaseType.Name!=typeof(Enum).Name)
    {
    抛出新异常(“不是枚举”);
    }
    返回(T)Enum.Parse(typeof(T),value,true);
    }
    公共静态T ToEnum(此int值)
    {
    if(typeof(T).BaseType.Name!=typeof(Enum).Name)
    {
    抛出新异常(“不是枚举”);
    }
    返回(T)Enum.ToObject(typeof(T),value);
    }
    

    现在可以随意使用枚举。

    我建议使用
    ISO639Code
    作为类,而不是枚举:

    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;
        }
    }
    
    然后让全局
    列表
    包含所有可能的代码,要根据代码名或值查找特定代码,只需在列表中搜索即可


    就我个人而言,我更喜欢这样做,而不是调整枚举。

    Anton,只是一个问题。如何使用此属性?i、 来自另一个班级。我认为这看起来很干净。@Sheldon您需要使用反射和
    属性。GetCustomAttribute
    ,通常将此数据缓存在内存中的某个位置,以避免每次我与Sheldon有相同的问题时都进行计算。非常感谢@Marc Gravelt查看
    描述属性
    :感谢malio。但我想知道的是C#,而不是.net framework命名空间。但问题是,通常有更好的方法来表示某些结构,但这完全取决于它们的使用方式。对于语言,CultureInfo类exists.true,但在许多方面,现有代码都非常可读。很明显,它是如何映射的。当然,可维护性是一个痛处,因为您可以很容易地进行交换或键入。我认为代码属性应该是只读的,因为在实体生命周期(对于这种特殊情况)有效参数时更改代码是没有意义的,这段代码是作为示例给出的,但不确定这里的全部范围。很好。那么如何将“af”直接映射到南非荷兰语呢?我应该通过*.GetDescription搜索所有枚举成员吗?是要动态分配描述还是按描述值搜索所有枚举条目?在这种情况下,您必须实现方法GetByDescription(此枚举currentEnum,字符串描述),我希望。。。ISO639编码l,m;k、 设定值(“af”);m=ISO639Code.Afrikaans;如果(k==m){messagebox.show(“equal.”);}this.To search by description value您必须实现
    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;
        }
    }