Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我的枚举可以有友好的名称吗?_C#_Enums - Fatal编程技术网

C# 我的枚举可以有友好的名称吗?

C# 我的枚举可以有友好的名称吗?,c#,enums,C#,Enums,我有以下enum public enum myEnum { ThisNameWorks, This Name doesn't work Neither.does.this; } 是否不可能将枚举与“友好名称”一起使用?它们遵循与变量名称相同的命名规则。 因此,它们不应包含空格 也是你建议的非常糟糕的做法。< /P> < p>枚举值名称必须遵循与C语言中所有标识符相同的命名规则,因此只有第一个名称是正确的。< p>枚举名称与正常变量名相同的规则,即在名称中间没有空格或点

我有以下
enum

public enum myEnum
{
    ThisNameWorks, 
    This Name doesn't work
    Neither.does.this;
}

是否不可能将
枚举
与“友好名称”一起使用?

它们遵循与变量名称相同的命名规则。 因此,它们不应包含空格


也是你建议的非常糟糕的做法。< /P> < p>枚举值名称必须遵循与C语言中所有标识符相同的命名规则,因此只有第一个名称是正确的。

< p>枚举名称与正常变量名相同的规则,即在名称中间没有空格或点…我仍然认为第一个是相当友好的……

< p>不,但是你可以用它来完成你要找的东西。

你可以使用<代码>描述< /C>属性获得那个友好的名字。您可以使用以下代码:

public enum myEnum
{
         ThisNameWorks, 
         This_Name_can_be_used_instead,

}
public static string ToStringEnums(Enum en)
{
    Type type = en.GetType();

    MemberInfo[] memInfo = type.GetMember(en.ToString());
    if (memInfo != null && memInfo.Length > 0)
    {
        object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (attrs != null && attrs.Length > 0)
            return ((DescriptionAttribute)attrs[0]).Description;
    }
    return en.ToString();
}
您希望使用此方法的示例:当您的枚举值为
EncryptionProviderType
并且希望
enumVar.Tostring()
返回“加密提供程序类型”时

先决条件:所有枚举成员都应使用属性
[说明(“Tostring()返回的字符串”)

示例枚举:

enum ExampleEnum
{
    [Description("One is one")]
    ValueOne = 1,
    [Description("Two is two")]
    ValueTow = 2
}
在你的课堂上,你会这样使用它:

ExampleEnum enumVar = ExampleEnum.ValueOne;
Console.WriteLine(ToStringEnums(enumVar));
public enum MyEnum
{
    [Description("Description for Foo")]
    Foo,
    [Description("Description for Bar")]
    Bar
}

MyEnum x = MyEnum.Foo;
string description = x.GetDescription();

我假设您希望向用户显示您的枚举值,因此,您希望它们具有友好的名称

以下是我的建议:

使用枚举类型模式。尽管实施起来需要一些努力,但它确实是值得的

public class MyEnum
{  
    public static readonly MyEnum Enum1=new MyEnum("This will work",1);
    public static readonly MyEnum Enum2=new MyEnum("This.will.work.either",2);
    public static readonly MyEnum[] All=new []{Enum1,Enum2};
    private MyEnum(string name,int value)
    {
        Name=name;
        Value=value;
    }

    public string Name{get;set;}
    public int Value{get;set;}

    public override string ToString()
    {
        return Name;    
    }
}

正如尤里建议的那样,您可以使用
Description
属性。以下扩展方法可以轻松获取枚举给定值的描述:

public static string GetDescription(this Enum value)
{
    Type type = value.GetType();
    string name = Enum.GetName(type, value);
    if (name != null)
    {
        FieldInfo field = type.GetField(name);
        if (field != null)
        {
            DescriptionAttribute attr = 
                   Attribute.GetCustomAttribute(field, 
                     typeof(DescriptionAttribute)) as DescriptionAttribute;
            if (attr != null)
            {
                return attr.Description;
            }
        }
    }
    return null;
}
您可以这样使用它:

ExampleEnum enumVar = ExampleEnum.ValueOne;
Console.WriteLine(ToStringEnums(enumVar));
public enum MyEnum
{
    [Description("Description for Foo")]
    Foo,
    [Description("Description for Bar")]
    Bar
}

MyEnum x = MyEnum.Foo;
string description = x.GetDescription();

如果您具有以下枚举:

public enum MyEnum {
    First,
    Second,
    Third
}
您可以为
MyEnum
声明扩展方法(就像您可以为任何其他类型声明扩展方法一样)。我刚把这件事提出来:

namespace Extension {
    public static class ExtensionMethods {
        public static string EnumValue(this MyEnum e) {
            switch (e) {
                case MyEnum.First:
                    return "First Friendly Value";
                case MyEnum.Second:
                    return "Second Friendly Value";
                case MyEnum.Third:
                    return "Third Friendly Value";
            }
            return "Horrible Failure!!";
        }
    }
}
使用此扩展方法,以下内容现在是合法的:

Console.WriteLine(MyEnum.First.EnumValue());

希望这有帮助

这个技巧的一个问题是描述属性无法本地化。我很喜欢Sacha Barber的一项技术,他创建了自己版本的Description属性,该属性将从相应的资源管理器中获取值


尽管本文讨论了WPF开发人员在绑定到Enum时通常会遇到的问题,但您可以直接跳到他创建LocalizableDescriptionAttribute的部分。

已经发布了一些很好的解决方案。当我遇到这个问题时,我想采用两种方法:将枚举转换为描述,并将与描述匹配的字符串转换为枚举

我有两种变体,慢速和快速。两者都从枚举转换为字符串,从字符串转换为枚举。我的问题是,我有这样的枚举,其中有些元素需要属性,而有些不需要。我不想在不需要属性的元素上添加属性。我目前总共有大约一百个:

public enum POS
{   
    CC, //  Coordinating conjunction
    CD, //  Cardinal Number
    DT, //  Determiner
    EX, //  Existential there
    FW, //  Foreign Word
    IN, //  Preposision or subordinating conjunction
    JJ, //  Adjective
    [System.ComponentModel.Description("WP$")]
    WPDollar, //$   Possessive wh-pronoun
    WRB, //     Wh-adverb
    [System.ComponentModel.Description("#")]
    Hash,
    [System.ComponentModel.Description("$")]
    Dollar,
    [System.ComponentModel.Description("''")]
    DoubleTick,
    [System.ComponentModel.Description("(")]
    LeftParenth,
    [System.ComponentModel.Description(")")]
    RightParenth,
    [System.ComponentModel.Description(",")]
    Comma,
    [System.ComponentModel.Description(".")]
    Period,
    [System.ComponentModel.Description(":")]
    Colon,
    [System.ComponentModel.Description("``")]
    DoubleBackTick,
    };
处理这个问题的第一种方法是缓慢的,它基于我在这里和网上看到的建议。它的速度很慢,因为我们正在反思每一次转换:

using System;
using System.Collections.Generic;
namespace CustomExtensions
{

/// <summary>
/// uses extension methods to convert enums with hypens in their names to underscore and other variants
public static class EnumExtensions
{
    /// <summary>
    /// Gets the description string, if available. Otherwise returns the name of the enum field
    /// LthWrapper.POS.Dollar.GetString() yields "$", an impossible control character for enums
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string GetStringSlow(this Enum value)
    {
        Type type = value.GetType();
        string name = Enum.GetName(type, value);
        if (name != null)
        {
            System.Reflection.FieldInfo field = type.GetField(name);
            if (field != null)
            {
                System.ComponentModel.DescriptionAttribute attr =
                       Attribute.GetCustomAttribute(field,
                         typeof(System.ComponentModel.DescriptionAttribute)) as System.ComponentModel.DescriptionAttribute;
                if (attr != null)
                {
                    //return the description if we have it
                    name = attr.Description; 
                }
            }
        }
        return name;
    }

    /// <summary>
    /// Converts a string to an enum field using the string first; if that fails, tries to find a description
    /// attribute that matches. 
    /// "$".ToEnum<LthWrapper.POS>() yields POS.Dollar
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T ToEnumSlow<T>(this string value) //, T defaultValue)
    {
        T theEnum = default(T);

        Type enumType = typeof(T);

        //check and see if the value is a non attribute value
        try
        {
            theEnum = (T)Enum.Parse(enumType, value);
        }
        catch (System.ArgumentException e)
        {
            bool found = false;
            foreach (T enumValue in Enum.GetValues(enumType))
            {
                System.Reflection.FieldInfo field = enumType.GetField(enumValue.ToString());

                System.ComponentModel.DescriptionAttribute attr =
                           Attribute.GetCustomAttribute(field,
                             typeof(System.ComponentModel.DescriptionAttribute)) as System.ComponentModel.DescriptionAttribute;

                if (attr != null && attr.Description.Equals(value))
                {
                    theEnum = enumValue;
                    found = true;
                    break;

                }
            }
            if( !found )
                throw new ArgumentException("Cannot convert " + value + " to " + enumType.ToString());
        }

        return theEnum;
    }
}
}
使用系统;
使用System.Collections.Generic;
命名空间自定义扩展
{
/// 
///使用扩展方法将名称中带有hypens的枚举转换为下划线和其他变体
公共静态类枚举扩展
{
/// 
///获取描述字符串(如果可用)。否则返回枚举字段的名称
///LthWrapper.POS.Dollar.GetString()生成“$”,这是枚举不可能使用的控制字符
/// 
/// 
/// 
公共静态字符串GetStringSlow(此枚举值)
{
Type Type=value.GetType();
字符串名称=Enum.GetName(类型、值);
if(name!=null)
{
System.Reflection.FieldInfo字段=type.GetField(名称);
如果(字段!=null)
{
System.ComponentModel.DescriptionAttribute属性属性=
属性。GetCustomAttribute(字段,
类型(System.ComponentModel.DescriptionAttribute))为System.ComponentModel.DescriptionAttribute;
如果(attr!=null)
{
//如果我们有描述,请返回它
名称=属性描述;
}
}
}
返回名称;
}
/// 
///首先使用字符串将字符串转换为枚举字段;如果失败,则尝试查找描述
///匹配的属性。
///“$”.ToEnum()产生美元位置
/// 
/// 
/// 
/// 
公共静态T ToEnumSlow(此字符串值)/,T defaultValue)
{
T theEnum=默认值(T);
类型enumType=typeof(T);
//检查并查看该值是否为非属性值
尝试
{
theEnum=(T)Enum.Parse(enumType,value);
}
catch(System.e)
{
bool-found=false;
foreach(Enum.GetValues(enumType)中的T enumValue)
{
System.Reflection.FieldInfo field=enumType.GetField(enumValue.ToString());
System.ComponentModel.DescriptionAttribute属性属性=
属性。GetCustomAttribute(字段,
类型(System.ComponentModel.DescriptionAttribute))为System.ComponentModel.DescriptionAttribute;
if(attr!=null&&attr.Description.Equals(value))
{
theEnum=枚举值;
发现=真;
打破
}
}
如果(!找到)
抛出新ArgumentException(“无法将“+value+”转换为“+enumType.ToString());
}
返回数值;
}
}
}
问题是你每次都在做反射。我还没有衡量这样做对性能的影响,但这似乎令人担忧。更糟糕的是,我们重复计算这些昂贵的转换,而不缓存它们

相反,w
    public enum myEnum
{
    ThisNameWorks,
    ThisNameDoesntWork149141331,// This Name doesn't work
    NeitherDoesThis1849204824// Neither.does.this;
}

class Program
{
    private static unsafe void ChangeString(string original, string replacement)
    {
        if (original.Length < replacement.Length)
            throw new ArgumentException();

        fixed (char* pDst = original)
        fixed (char* pSrc = replacement)
        {
            // Update the length of the original string
            int* lenPtr = (int*)pDst;
            lenPtr[-1] = replacement.Length;

            // Copy the characters
            for (int i = 0; i < replacement.Length; i++)
                pDst[i] = pSrc[i];
        }
    }

    public static unsafe void Initialize()
    {
        ChangeString(myEnum.ThisNameDoesntWork149141331.ToString(), "This Name doesn't work");
        ChangeString(myEnum.NeitherDoesThis1849204824.ToString(), "Neither.does.this");
    }

    static void Main(string[] args)
    {
        Console.WriteLine(myEnum.ThisNameWorks);
        Console.WriteLine(myEnum.ThisNameDoesntWork149141331);
        Console.WriteLine(myEnum.NeitherDoesThis1849204824);

        Initialize();

        Console.WriteLine(myEnum.ThisNameWorks);
        Console.WriteLine(myEnum.ThisNameDoesntWork149141331);
        Console.WriteLine(myEnum.NeitherDoesThis1849204824);
    }
public static class EnumHelper
{
    public static string ToDescription(Enum value)
    {
        if (value == null)
        {
            return string.Empty;
        }

        if (!Enum.IsDefined(value.GetType(), value))
        {
            return string.Empty;
        }

        FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
        if (fieldInfo != null)
        {
            DescriptionAttribute[] attributes =
                fieldInfo.GetCustomAttributes(typeof (DescriptionAttribute), false) as DescriptionAttribute[];
            if (attributes != null && attributes.Length > 0)
            {
                return attributes[0].Description;
            }
        }

        return StringHelper.ToFriendlyName(value.ToString());
    }
}

public static class StringHelper
{
    public static bool IsNullOrWhiteSpace(string value)
    {
        return value == null || string.IsNullOrEmpty(value.Trim());
    }

    public static string ToFriendlyName(string value)
    {
        if (value == null) return string.Empty;
        if (value.Trim().Length == 0) return string.Empty;

        string result = value;

        result = string.Concat(result.Substring(0, 1).ToUpperInvariant(), result.Substring(1, result.Length - 1));

        const string pattern = @"([A-Z]+(?![a-z])|\d+|[A-Z][a-z]+|(?![A-Z])[a-z]+)+";

        List<string> words = new List<string>();
        Match match = Regex.Match(result, pattern);
        if (match.Success)
        {
            Group group = match.Groups[1];
            foreach (Capture capture in group.Captures)
            {
                words.Add(capture.Value);
            }
        }

        return string.Join(" ", words.ToArray());
    }
}


    [TestMethod]
    public void TestFriendlyName()
    {
        string[][] cases =
            {
                new string[] {null, string.Empty},
                new string[] {string.Empty, string.Empty},
                new string[] {" ", string.Empty}, 
                new string[] {"A", "A"},
                new string[] {"z", "Z"},

                new string[] {"Pascal", "Pascal"},
                new string[] {"camel", "Camel"},

                new string[] {"PascalCase", "Pascal Case"}, 
                new string[] {"ABCPascal", "ABC Pascal"}, 
                new string[] {"PascalABC", "Pascal ABC"}, 
                new string[] {"Pascal123", "Pascal 123"}, 
                new string[] {"Pascal123ABC", "Pascal 123 ABC"}, 
                new string[] {"PascalABC123", "Pascal ABC 123"}, 
                new string[] {"123Pascal", "123 Pascal"}, 
                new string[] {"123ABCPascal", "123 ABC Pascal"}, 
                new string[] {"ABC123Pascal", "ABC 123 Pascal"}, 

                new string[] {"camelCase", "Camel Case"}, 
                new string[] {"camelABC", "Camel ABC"}, 
                new string[] {"camel123", "Camel 123"}, 
            };

        foreach (string[] givens in cases)
        {
            string input = givens[0];
            string expected = givens[1];
            string output = StringHelper.ToFriendlyName(input);

            Assert.AreEqual(expected, output);
        }
    }
}