質問
列挙値を人間が読める値に変換する方法を知っている人はいますか?
例えば:
ThisIsValueA は「これは値 A」である必要があります。
解決
これは、Ian Horwill 氏が残した vb コード スニペットから変換したものです。 かなり前のブログ投稿...それ以来、これを運用環境でうまく使用しています。
/// <summary>
/// Add spaces to separate the capitalized words in the string,
/// i.e. insert a space before each uppercase letter that is
/// either preceded by a lowercase letter or followed by a
/// lowercase letter (but not for the first char in string).
/// This keeps groups of uppercase letters - e.g. acronyms - together.
/// </summary>
/// <param name="pascalCaseString">A string in PascalCase</param>
/// <returns></returns>
public static string Wordify(string pascalCaseString)
{
Regex r = new Regex("(?<=[a-z])(?<x>[A-Z])|(?<=.)(?<x>[A-Z])(?=[a-z])");
return r.Replace(pascalCaseString, " ${x}");
}
(「System.Text. RegularExpressions を使用する」が必要です;)
したがって:
Console.WriteLine(Wordify(ThisIsValueA.ToString()));
戻ってきます、
"This Is Value A".
これは、Description 属性を指定するよりもはるかに単純で、冗長性が低くなります。
ここで属性は、間接層を提供する必要がある場合にのみ役立ちます (質問では求められていませんでした)。
他のヒント
Enums の .ToString は C# では比較的遅く、GetType().Name に匹敵します (これを内部で使用する可能性もあります)。
ソリューションを非常に高速または高効率にする必要がある場合は、変換を静的辞書にキャッシュし、そこから検索するのが最善の方法かもしれません。
C#3 を活用するために @Leon のコードを少し改変したもの。これは列挙型の拡張として意味があります。列挙型のすべてを乱雑にしたくない場合は、これを特定の型に制限することができます。
public static string Wordify(this Enum input)
{
Regex r = new Regex("(?<=[a-z])(?<x>[A-Z])|(?<=.)(?<x>[A-Z])(?=[a-z])");
return r.Replace( input.ToString() , " ${x}");
}
//then your calling syntax is down to:
MyEnum.ThisIsA.Wordify();
私が見たこの例のほとんどには、列挙値を [Description] 属性でマークアップし、リフレクションを使用して値と説明の間で「変換」を行うことが含まれます。これについての古いブログ投稿は次のとおりです。
http://geekswithblogs.net/rakker/archive/2006/05/19/78952.aspx
System.Reflection の「Attribute」クラスを継承して、独自の「Description」クラスを作成できます。このように(から ここ):
using System;
using System.Reflection;
namespace FunWithEnum
{
enum Coolness : byte
{
[Description("Not so cool")]
NotSoCool = 5,
Cool, // since description same as ToString no attr are used
[Description("Very cool")]
VeryCool = NotSoCool + 7,
[Description("Super cool")]
SuperCool
}
class Description : Attribute
{
public string Text;
public Description(string text)
{
Text = text;
}
}
class Program
{
static string GetDescription(Enum en)
{
Type type = en.GetType();
MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(Description), false);
if (attrs != null && attrs.Length > 0)
return ((Description)attrs[0]).Text;
}
return en.ToString();
}
static void Main(string[] args)
{
Coolness coolType1 = Coolness.Cool;
Coolness coolType2 = Coolness.NotSoCool;
Console.WriteLine(GetDescription(coolType1));
Console.WriteLine(GetDescription(coolType2));
}
}
}
この記事もご覧ください。 http://www.codeproject.com/KB/cs/enumdatabinding.aspx
これは特にデータ バインディングに関するものですが、属性を使用して列挙値を修飾する方法を示し、属性のテキストを取得するための "GetDescription" メソッドを提供します。組み込みの description 属性を使用する場合の問題は、その属性を他の用途/ユーザーが使用するため、表示したくない場所に説明が表示される可能性があることです。カスタム属性はその問題を解決します。
ThisIsValueA が This_Is_Value_A になるように、アンダー スコアを使用して enum 値を定義するのが最善であることがわかりました。その後、enumValue.toString().Replace("_"," ") を実行するだけで済みます。ここで enumValue は変数です。
追加の代替案 Description
各列挙型に属性を追加すると、拡張メソッドが作成されます。Adam の「Coolness」列挙型を再利用するには:
public enum Coolness
{
NotSoCool,
Cool,
VeryCool,
SuperCool
}
public static class CoolnessExtensions
{
public static string ToString(this Coolness coolness)
{
switch (coolness)
{
case Coolness.NotSoCool:
return "Not so cool";
case Coolness.Cool:
return "Cool";
case Coolness.VeryCool:
return "Very cool";
case Coolness.SuperCool:
return Properties.Settings.Default["SuperCoolDescription"].ToString();
default:
throw new ArgumentException("Unknown amount of coolness", nameof(coolness));
}
}
}
これは、説明が実際の値から遠く離れていることを意味しますが、ローカリゼーションを使用して、言語ごとに異なる文字列を出力することができます。 VeryCool
例。