C# 自定义枚举分析

C# 自定义枚举分析,c#,enums,C#,Enums,我的枚举如下: public enum MyEnum { One, Two, Three} 我想将一些字符串与上面的enum进行比较,例如,下面的字符串将被解析为MyEnum。两个: "Two", "TWO", "Second", "2" 我知道我可以维护一个映射函数来完成这项工作。然而,我只是想找到一种更好的方法,例如,重写Enum.Parse函数,或者类似的方法。我曾尝试使用IConvertable,但似乎不可能。有什么想法吗 [AttributeUsage(AttributeTa

我的枚举如下:

public enum MyEnum {  One,  Two,  Three}
我想将一些字符串与上面的enum进行比较,例如,下面的字符串将被解析为MyEnum。两个:

"Two", "TWO", "Second", "2"
我知道我可以维护一个映射函数来完成这项工作。然而,我只是想找到一种更好的方法,例如,重写Enum.Parse函数,或者类似的方法。我曾尝试使用IConvertable,但似乎不可能。有什么想法吗

[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
public class NameAttribute : Attribute
{
    public readonly string[] Names;

    public NameAttribute(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException();
        }

        Names = new[] { name };
    }

    public NameAttribute(params string[] names)
    {
        if (names == null || names.Any(x => x == null))
        {
            throw new ArgumentNullException();
        }

        Names = names;
    }
}

public static class ParseEnum
{
    public static TEnum Parse<TEnum>(string value) where TEnum : struct
    {
        return ParseEnumImpl<TEnum>.Values[value];
    }

    public static bool TryParse<TEnum>(string value, out TEnum result) where TEnum : struct
    {
        return ParseEnumImpl<TEnum>.Values.TryGetValue(value, out result);
    }

    private static class ParseEnumImpl<TEnum> where TEnum : struct
    {
        public static readonly Dictionary<string, TEnum> Values = new Dictionary<string,TEnum>();

        static ParseEnumImpl()
        {
            var nameAttributes = typeof(TEnum)
                .GetFields()
                .Select(x => new 
                { 
                    Value = x, 
                    Names = x.GetCustomAttributes(typeof(NameAttribute), false)
                        .Cast<NameAttribute>() 
                });

            var degrouped = nameAttributes.SelectMany(
                x => x.Names.SelectMany(y => y.Names), 
                (x, y) => new { Value = x.Value, Name = y });

            Values = degrouped.ToDictionary(
                x => x.Name, 
                x => (TEnum)x.Value.GetValue(null));
        }
    }
}

TestEnum r1=ParseEnum.Parse(“XF”);
睾丸r2;
boolr3=ParseEnum.TryParse(“YB”,out r2);

请注意,使用内部类(
ParseEnumImpl
)来缓存
TEnum
“名称”。

最好的方法就是存储一个带有映射的
字典:

static Dictionary<string, string> _mappings = new Dictionary<string, string>
{
    { "Two", "Two" },
    { "Second", "Two" },
    { "2", "Two" }
};
通常,我更喜欢简单的解决方案,因为它们比“重写
Enum.Parse
函数或类似的东西”更容易理解

但是我们可以通过使用
字典
,做得更简单:


后一种方法还提高了性能,因为我们避免了调用
Enum.Parse

您尝试分析两种不同的情况:

  • 输入包含枚举的名称
  • 输入包含枚举的值
  • 如果输入中只有这两种情况,则可以简单地使用尝试以不区分大小写的方式解析文本:

    MyEnum output;
    if (Enum.TryParse(input,true,out output))
    {
        // Process succesful value
    }
    
    C#7+Update:现在可以在同一行中声明变量:

    if (Enum.TryParse(input,true,out var output))
    {
        // Process succesful value
    }
    
    从文档示例中,您可以看到
    TryParse
    可以处理文本和数字字符串输入

    至于解析
    Second
    ,除了在编码者的头脑中,本文与枚举没有任何关系。在这种情况下,您实际上需要创建一个映射并将其放置在某个位置—字典、自定义属性等


    事实上,如果数据来自外部文件,这是一个ETL问题,而不是解析问题。在这种情况下,典型的解决方案是创建查找表,将输入映射到已识别的输出,并在解析之前用查找值替换输入。您可以使用nuget package Enums.NET对Description属性执行反向查找

    注意,有一个带有ignoreCase布尔值的重载

    public enum PhoneCode
    {
        [DescriptionAttribute("991")]
        Emergency,
        [DescriptionAttribute("411")]
        Info,
    }
    
    PhoneCode code;
    EnumsNET.Enums.TryParse("991", out code, EnumsNET.EnumFormat.Description)
    

    虽然我确实喜欢这些属性,但我自己使用了一个映射,而是扩展了
    字符串
    基类型,如下所示:

    public enum Rating
    {
        High,
        Medium,
        Low,
        Other
    };
    
    然后我有了一个
    静态的
    类作为我的扩展。。。其中包含以下代码:

    public static Dictionary<string, Rating> RatingsMap = new Dictionary<string, Rating>()
    {
        {"Highly recommended", Rating.High},
        {"Ok", Rating.Medium},
        {"Liked", Rating.Medium},
        {"Thumbs down", Rating.Low}
    };
    
    public static Rating ToRating(this string me)
    {
        Rating retval = Rating.Other;
    
        if (EXTENSIONS.RatingsMap.ContainsKey(me))
            retval = EXTENSIONS.RatingsMap[me];
    
        return retval;
    }
    
    public static Dictionary RatingsMap=new Dictionary()
    {
    {“高度推荐”,评级为.High},
    {“Ok”,评级.中等},
    {“喜欢”,评级.中等},
    {“拇指朝下”,评级为.Low}
    };
    公共静态额定值ToRating(此字符串为me)
    {
    额定值retval=额定值。其他;
    if(扩展额定值映射容器(me))
    retval=EXTENSIONS.RatingsMap[me];
    返回返回;
    }
    
    我知道我可以维护映射功能来完成这项工作。这一个:-)请注意,有一长串类似的问题:您可以使用描述属性,如本问题中所述,“Second”和MyEnum.Two之间没有任何关系,因此请查看链接的问题。各位,这不是重复的。请在结束前仔细阅读。
    MyEnum output;
    if (Enum.TryParse(input,true,out output))
    {
        // Process succesful value
    }
    
    if (Enum.TryParse(input,true,out var output))
    {
        // Process succesful value
    }
    
    public enum PhoneCode
    {
        [DescriptionAttribute("991")]
        Emergency,
        [DescriptionAttribute("411")]
        Info,
    }
    
    PhoneCode code;
    EnumsNET.Enums.TryParse("991", out code, EnumsNET.EnumFormat.Description)
    
    public enum Rating
    {
        High,
        Medium,
        Low,
        Other
    };
    
    public static Dictionary<string, Rating> RatingsMap = new Dictionary<string, Rating>()
    {
        {"Highly recommended", Rating.High},
        {"Ok", Rating.Medium},
        {"Liked", Rating.Medium},
        {"Thumbs down", Rating.Low}
    };
    
    public static Rating ToRating(this string me)
    {
        Rating retval = Rating.Other;
    
        if (EXTENSIONS.RatingsMap.ContainsKey(me))
            retval = EXTENSIONS.RatingsMap[me];
    
        return retval;
    }