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