Enumerationの型はintでなければならないため、以下は不可能であることを知っています
enum GroupTypes
{
TheGroup = "OEM",
TheOtherGroup = "CMB"
}
私のデータベースからは、包括的なコード(OEMおよびCMB s)を。私はこの分野をenum何か他の理解できるものにしたいと思います。ターゲットが可読性である場合、ソリューションは簡潔である必要があるためです。
他にどのようなオプションがありますか?
Enumerationの型はintでなければならないため、以下は不可能であることを知っています
enum GroupTypes
{
TheGroup = "OEM",
TheOtherGroup = "CMB"
}
私のデータベースからは、包括的なコード(OEMおよびCMB s)を。私はこの分野をenum何か他の理解できるものにしたいと思います。ターゲットが可読性である場合、ソリューションは簡潔である必要があるためです。
他にどのようなオプションがありますか?
回答:
列挙型のように見えるので、メソッドではなくクラスでプロパティを使用するのが好きです。
ロガーの例を次に示します。
public class LogCategory
{
private LogCategory(string value) { Value = value; }
public string Value { get; set; }
public static LogCategory Trace { get { return new LogCategory("Trace"); } }
public static LogCategory Debug { get { return new LogCategory("Debug"); } }
public static LogCategory Info { get { return new LogCategory("Info"); } }
public static LogCategory Warning { get { return new LogCategory("Warning"); } }
public static LogCategory Error { get { return new LogCategory("Error"); } }
}
タイプセーフな文字列値をパラメーターとして渡します。
public static void Write(string message, LogCategory logCategory)
{
var log = new LogEntry { Message = message };
Logger.Write(log, logCategory.Value);
}
使用法:
Logger.Write("This is almost like an enum.", LogCategory.Info);
ToStringメソッドをオーバーライドしてreturnを返しましたValue。そして、文字列への暗黙のキャスト演算子を提供しました。public static implicit operator String(LogCategory category) { return Value; }。
拡張モデルを使用することもできます。
public enum MyEnum
{
[Description("String 1")]
V1= 1,
[Description("String 2")]
V2= 2
}
あなたの拡張クラス
public static class MyEnumExtensions
{
public static string ToDescriptionString(this MyEnum val)
{
DescriptionAttribute[] attributes = (DescriptionAttribute[])val
.GetType()
.GetField(val.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : string.Empty;
}
}
使用法:
MyEnum myLocal = MyEnum.V1;
print(myLocal.ToDescriptionString());
public static string ToDescriptionString(this Enum ...明示的にに入力せずにieを使用しMyEnumます。
定数で静的クラスを使用するのはどうですか?
static class GroupTypes
{
public const string TheGroup = "OEM";
public const string TheOtherGroup = "CMB";
}
void DoSomething(string groupType)
{
if(groupType == GroupTypes.TheGroup)
{
// Be nice
}
else if (groupType == GroupTypes.TheOtherGroup)
{
// Continue to be nice
}
else
{
// unexpected, throw exception?
}
}
GroupTypes静的クラスであるため、引数型として渡すことはできません。それがミエンの答えでさえ解決する問題です。この場合、あなたの代わりに持っている必要があるだろうvoid DoSomething(string groupType)し、その手段groupTypeかもしれないいかなる文字列値を使用すると、これらの無効なタイプのために準備する必要があり、それらをどのように処理するかを決める手段としても価値は、あなたが期待されていないことを、(たとえば、例外をスローすることによって)。Mienの答えでさえ、有効な入力の数をLogCategoryクラスで定義されたオプションに制限することでそれを解決します。
列挙型の項目に属性を追加し、リフレクションを使用して属性から値を取得できます。
次のように、「フィールド」指定子を使用して属性を適用する必要があります。
enum GroupTypes
{
[field:Description("OEM")]
TheGroup,
[field:Description("CMB")]
TheOtherGroup
}
次に、列挙型の静的フィールド(この場合はGroupTypes)をリフレクトし、DescriptionAttributeリフレクションを使用して探していた値のを取得します。
public static DescriptionAttribute GetEnumDescriptionAttribute<T>(
this T value) where T : struct
{
// The type of the enum, it will be reused.
Type type = typeof(T);
// If T is not an enum, get out.
if (!type.IsEnum)
throw new InvalidOperationException(
"The type parameter T must be an enum type.");
// If the value isn't defined throw an exception.
if (!Enum.IsDefined(type, value))
throw new InvalidEnumArgumentException(
"value", Convert.ToInt32(value), type);
// Get the static field for the value.
FieldInfo fi = type.GetField(value.ToString(),
BindingFlags.Static | BindingFlags.Public);
// Get the description attribute, if there is one.
return fi.GetCustomAttributes(typeof(DescriptionAttribute), true).
Cast<DescriptionAttribute>().SingleOrDefault();
}
私は返すことを選びました DescriptionAttribute属性が適用されているかどうかを判断できるようにしたい場合は、上記それ自体ました。
実際にはとても簡単にできます。次のコードを使用します。
enum GroupTypes
{
OEM,
CMB
};
次に、各列挙型要素の文字列値を取得する場合は、次のコード行を使用します。
String oemString = Enum.GetName(typeof(GroupTypes), GroupTypes.OEM);
私は過去にこのメソッドをうまく使用しており、定数クラスを使用して文字列定数を保持したこともありますが、どちらもかなりうまくいきますが、私はこれを好む傾向があります。
静的クラスに定数を追加してみてください。Typeで終わるわけではありませんが、読みやすく整理された定数があります。
public static class GroupTypes {
public const string TheGroup = "OEM";
public const string TheOtherGroup = "CMB";
}
以下を含むDB用に2つ目の列挙型を作成します。
enum DBGroupTypes
{
OEM = 0,
CMB = 1
}
これで、Enum.Parseを使用して、文字列 "OEM"および "CMB"から正しいDBGroupTypes値を取得できます。次に、それらをintに変換し、モデルでさらに使用したい正しい列挙から正しい値を取得できます。
クラスを使用します。
編集:より良い例
class StarshipType
{
private string _Name;
private static List<StarshipType> _StarshipTypes = new List<StarshipType>();
public static readonly StarshipType Ultralight = new StarshipType("Ultralight");
public static readonly StarshipType Light = new StarshipType("Light");
public static readonly StarshipType Mediumweight = new StarshipType("Mediumweight");
public static readonly StarshipType Heavy = new StarshipType("Heavy");
public static readonly StarshipType Superheavy = new StarshipType("Superheavy");
public string Name
{
get { return _Name; }
private set { _Name = value; }
}
public static IList<StarshipType> StarshipTypes
{
get { return _StarshipTypes; }
}
private StarshipType(string name, int systemRatio)
{
Name = name;
_StarshipTypes.Add(this);
}
public static StarshipType Parse(string toParse)
{
foreach (StarshipType s in StarshipTypes)
{
if (toParse == s.Name)
return s;
}
throw new FormatException("Could not parse string.");
}
}
この問題に対処するもう1つの方法は、列挙値と文字列の配列を使用して、列挙値を文字列のリストにマッピングすることです。
public enum GroupTypes
{
TheGroup = 0,
TheOtherGroup
}
string[] GroupTypesStr = {
"OEM",
"CMB"
};
次のように使用できます。
Log.Write(GroupTypesStr[(int)GroupTypes.TheOtherGroup]);
それはCMBを促します
長所:
短所:
これは、列挙値を文字列として取得するために使用した拡張メソッドです。まずここに列挙型があります。
public enum DatabaseEnvironment
{
[Description("AzamSharpBlogDevDatabase")]
Development = 1,
[Description("AzamSharpBlogQADatabase")]
QualityAssurance = 2,
[Description("AzamSharpBlogTestDatabase")]
Test = 3
}
Description属性はSystem.ComponentModelから取得されました。
そして、これが私の拡張メソッドです:
public static string GetValueAsString(this DatabaseEnvironment environment)
{
// get the field
var field = environment.GetType().GetField(environment.ToString());
var customAttributes = field.GetCustomAttributes(typeof (DescriptionAttribute), false);
if(customAttributes.Length > 0)
{
return (customAttributes[0] as DescriptionAttribute).Description;
}
else
{
return environment.ToString();
}
}
これで、次のコードを使用して、enumに文字列値としてアクセスできます。
[TestFixture]
public class when_getting_value_of_enum
{
[Test]
public void should_get_the_value_as_string()
{
Assert.AreEqual("AzamSharpBlogTestDatabase",DatabaseEnvironment.Test.GetValueAsString());
}
}
辞書を使用してルックアップテーブルを検討しましたか?
enum GroupTypes
{
TheGroup,
TheOtherGroup
}
Dictionary<string, GroupTypes> GroupTypeLookup = new Dictionary<string, GroupTypes>();
// initialize lookup table:
GroupTypeLookup.Add("OEM", TheGroup);
GroupTypeLookup.Add("CMB", TheOtherGroup);
次に、GroupTypeLookup.TryGetValue()を使用して、文字列を読み取ったときに文字列を検索できます。
public class DataType
{
private readonly string value;
private static readonly Dictionary<string, DataType> predefinedValues;
public static readonly DataType Json = new DataType("json");
public static readonly DataType Xml = new DataType("xml");
public static readonly DataType Text = new DataType("text");
public static readonly DataType Html = new DataType("html");
public static readonly DataType Binary = new DataType("binary");
static DataType()
{
predefinedValues = new Dictionary<string, DataType>();
predefinedValues.Add(Json.Value, Json);
predefinedValues.Add(Xml.Value, Xml);
predefinedValues.Add(Text.Value, Text);
predefinedValues.Add(Html.Value, Html);
predefinedValues.Add(Binary.Value, Binary);
}
private DataType(string value)
{
this.value = value;
}
public static DataType Parse(string value)
{
var exception = new FormatException($"Invalid value for type {nameof(DataType)}");
if (string.IsNullOrEmpty(value))
throw exception;
string key = value.ToLower();
if (!predefinedValues.ContainsKey(key))
throw exception;
return predefinedValues[key];
}
public string Value
{
get { return value; }
}
}
C#は列挙された文字列をサポートしていませんが、ほとんどの状況では、リストまたは辞書を使用して目的の効果を得ることができます。
たとえば、合否結果を出力するには:
List<string> PassFail = new List<string> { "FAIL", "PASS" };
bool result = true;
Console.WriteLine("Test1: " + PassFail[result.GetHashCode()]);
私はそれをクラスにして、列挙型を完全に回避します。そして、typehandlerを使用すると、dbからオブジェクトを取得するときにオブジェクトを作成できます。
IE:
public class Group
{
public string Value{ get; set; }
public Group( string value ){ Value = value; }
public static Group TheGroup() { return new Group("OEM"); }
public static Group OtherGroup() { return new Group("CMB"); }
}
辞書を作成して、コードをキーとして使用します。
編集:逆引き(キーの検索)の実行に関するコメントに対処するには、これは非常に効率的ではありません。これが必要な場合は、それを処理する新しいクラスを作成します。
私の最初の質問-データベース自体にアクセスできますか?これはデータベースで正規化する必要があります。そうしないと、ソリューションがエラーを起こしやすくなります。私の経験では、「OEM」と「CMB」でいっぱいのデータフィールドは、「oem」と他の「がらくたデータ」のようなものが時間の経過とともに混合される傾向があります。...正規化できれば、キーを使用できますEnumとして要素を含むテーブルで、これで完了です。構造はよりすっきりしています。
それが利用できない場合は、Enumを作成し、文字列を解析してEnumに変換するクラスを作成します。これにより、少なくとも非標準エントリの処理にある程度の柔軟性が提供され、Enum.Parse / Reflection / etcを使用して回避策を実行するよりもエラーをトラップまたは処理する際の柔軟性が大幅に向上します。辞書は機能しますが、ケースの問題などが発生した場合に故障する可能性があります。
あなたができるようにクラスを書くことをお勧めします:
// I renamed this to GroupType, since it sounds like each element has a single type...
GroupType theType = GroupTypeParser.GetGroupType(theDBString);
これにより、DBを変更しなくても、ほとんどの可読性が維持されます。
私が正しく理解している場合は、文字列から列挙型への変換が必要です。
enum GroupTypes {
Unknown = 0,
OEM = 1,
CMB = 2
}
static GroupTypes StrToEnum(string str){
GroupTypes g = GroupTypes.Unknown;
try {
object o = Enum.Parse(typeof(GroupTypes), str, true);
g = (GroupTypes)(o ?? 0);
} catch {
}
return g;
}
// then use it like this
GroupTypes g1 = StrToEnum("OEM");
GroupTypes g2 = StrToEnum("bad value");
必要に応じて、enum型のジェネリックスを使用して、より豪華にすることができます。
Glennular拡張メソッドを少し調整したので、ENUM以外のものにも拡張を使用できます。
using System;
using System.ComponentModel;
namespace Extensions {
public static class T_Extensions {
/// <summary>
/// Gets the Description Attribute Value
/// </summary>
/// <typeparam name="T">Entity Type</typeparam>
/// <param name="val">Variable</param>
/// <returns>The value of the Description Attribute or an Empty String</returns>
public static string Description<T>(this T t) {
DescriptionAttribute[] attributes = (DescriptionAttribute[])t.GetType().GetField(t.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : string.Empty;
}
}
}
またはLinqを使用する
using System;
using System.ComponentModel;
using System.Linq;
namespace Extensions {
public static class T_Extensions {
public static string Description<T>(this T t) =>
((DescriptionAttribute[])t
?.GetType()
?.GetField(t?.ToString())
?.GetCustomAttributes(typeof(DescriptionAttribute), false))
?.Select(a => a?.Description)
?.FirstOrDefault()
?? string.Empty;
}
}
@Even Mienの回答に続いて、私はもう少し進んでGenericにしようとしましたが、ほとんどそこにあるようですが、1つのケースはまだ抵抗し、おそらくコードを少し単純化できます。
文字列から割り当てることができないため、私がどのように改善できるかを見て、特にそれを機能させることができる場合は、ここに投稿します
これまでのところ、私は次の結果を得ました:
Console.WriteLine(TestEnum.Test1);//displays "TEST1"
bool test = "TEST1" == TestEnum.Test1; //true
var test2 = TestEnum.Test1; //is TestEnum and has value
string test3 = TestEnum.Test1; //test3 = "TEST1"
var test4 = TestEnum.Test1 == TestEnum.Test2; //false
EnumType<TestEnum> test5 = "TEST1"; //works fine
//TestEnum test5 = "string"; DOESN'T compile .... :(:(
魔法が起こる場所:
public abstract class EnumType<T> where T : EnumType<T>
{
public string Value { get; set; }
protected EnumType(string value)
{
Value = value;
}
public static implicit operator EnumType<T>(string s)
{
if (All.Any(dt => dt.Value == s))
{
Type t = typeof(T);
ConstructorInfo ci = t.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null, new Type[] { typeof(string) }, null);
return (T)ci.Invoke(new object[] {s});
}
else
{
return null;
}
}
public static implicit operator string(EnumType<T> dt)
{
return dt?.Value;
}
public static bool operator ==(EnumType<T> ct1, EnumType<T> ct2)
{
return (string)ct1 == (string)ct2;
}
public static bool operator !=(EnumType<T> ct1, EnumType<T> ct2)
{
return !(ct1 == ct2);
}
public override bool Equals(object obj)
{
try
{
return (string)obj == Value;
}
catch
{
return false;
}
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public static IEnumerable<T> All
=> typeof(T).GetProperties()
.Where(p => p.PropertyType == typeof(T))
.Select(x => (T)x.GetValue(null, null));
}
私はそれから私の列挙のためにこれを宣言する必要があります:
public class TestEnum : EnumType<TestEnum>
{
private TestEnum(string value) : base(value)
{}
public static TestEnum Test1 { get { return new TestEnum("TEST1"); } }
public static TestEnum Test2 { get { return new TestEnum("TEST2"); } }
}
新ネットコア3.0 / C#8.0(作業環境は、あなたのプロジェクトをアップグレードすることを可能にする場合)ショートハンドスイッチ文があることルックスやや列挙っぽいです。結局のところ、これは何年にもわたって使用してきた古い退屈なswitchステートメントと同じです。
ここでの唯一の本当の違いは、switchステートメントが新しいスーツを得たことです。
public static RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
Rainbow.Green => new RGBColor(0x00, 0xFF, 0x00),
Rainbow.Blue => new RGBColor(0x00, 0x00, 0xFF),
Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
_ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};
ここからコピーした上記のコードは、実際には列挙型をパラメーターとして使用しています。
それはあなたが望むものではありません(そして信頼してください、私は長い間OPが要求しているものに似たものを望んでいました)が、これは実際にはMSからのオリーブのブランチのようなものだと感じています。JMO。
それが誰かを助けることを願っています!
私は前の回答でほのめかした構造を使用しましたが、複雑さは排除しました。私にとって、これは文字列の列挙を作成することに最も似ていました。列挙が使用されるのと同じ方法で使用されます。
struct ViewTypes
{
public const string View1 = "Whatever string you like";
public const string View2 = "another string";
}
使用例:
switch( some_string_variable )
{
case ViewTypes.View1: /* do something */ break;
case ViewTypes.View2: /* do something else */ break;
}
@Even(経由で示唆したように私もいくつか列挙型を実装class Xし、public static Xちょうどこの頃、ネット4.5開始、がありますことを、後で調べるために、メンバー)右 ToString()方法があります。
今、私はすべてを列挙型に再実装しています。
これは、厳密に型指定されたパラメーターまたは文字列として使用する方法です。
public class ClassLikeEnum
{
public string Value
{
get;
private set;
}
ClassLikeEnum(string value)
{
Value = value;
}
public static implicit operator string(ClassLikeEnum c)
{
return c.Value;
}
public static readonly ClassLikeEnum C1 = new ClassLikeEnum("RandomString1");
public static readonly ClassLikeEnum C2 = new ClassLikeEnum("RandomString2");
}
2つの列挙型を使用できます。1つはデータベース用、もう1つは可読性用です。
あなたは彼らが同期していることを確認する必要があるだけです、それは小さなコストのようです。値を設定する必要はなく、位置を同じに設定するだけですが、値を設定すると、2つの列挙型が関連していることが明確になり、列挙型メンバーの再配置によるエラーが防止されます。また、コメントにより、メンテナンスクルーはこれらが関連しており、同期を保つ必要があることを知ることができます。
// keep in sync with GroupTypes
public enum GroupTypeCodes
{
OEM,
CMB
}
// keep in sync with GroupTypesCodes
public enum GroupTypes
{
TheGroup = GroupTypeCodes.OEM,
TheOtherGroup = GroupTypeCodes.CMB
}
それを使用するには、まずコードに変換するだけです。
GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = ((GroupTypeCodes)myGroupType).ToString();
次に、さらに便利にしたい場合は、このタイプの列挙型でのみ機能する拡張関数を追加できます。
public static string ToString(this GroupTypes source)
{
return ((GroupTypeCodes)source).ToString();
}
そして、あなたはただ行うことができます:
GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = myGroupType.ToString();
enum場合、一方の意図した値の変更は、もう一方を誤って混乱させる可能性があります。
私は基本的に@ArthurCによる反射の答えを探していました
彼の答えを少し拡張するために、ジェネリック関数を使用することでさらに良くすることができます:
// If you want for a specific Enum
private static string EnumStringValue(GroupTypes e)
{
return EnumStringValue<GroupTypes>(e);
}
// Generic
private static string EnumStringValue<T>(T enumInstance)
{
return Enum.GetName(typeof(T), enumInstance);
}
次に、あなたが持っているものをラップするだけです
EnumStringValue(GroupTypes.TheGroup) // if you incorporate the top part
または
EnumStringValue<GroupTypes>(GroupTypes.TheGroup) // if you just use the generic
@EvenMienから取得し、コメントの一部に追加しました。(私自身の使用例でも)
public struct AgentAction
{
private AgentAction(string value) { Value = value; }
public string Value { get; private set; }
public override string ToString()
{
return this.Value;
}
public static AgentAction Login = new AgentAction("Logout");
public static AgentAction Logout = new AgentAction("Logout");
public static implicit operator string(AgentAction action) { return action.ToString(); }
}
このクラスを追加する
public class DatabasePreference {
public DatabasePreference([CallerMemberName] string preferenceName = "") {
PreferenceName = preferenceName;
}
public string PreferenceName;
}
この作業はCallerMemberName、コーディングを最小限に抑えるために使用されています
使用:
//Declare names
public static DatabasePreference ScannerDefaultFlashLight = new DatabasePreference();
public static DatabasePreference ScannerQrCodes = new DatabasePreference();
public static DatabasePreference Scanner1dCodes = new DatabasePreference();
試して:
Console.WriteLine(ScannerDefaultFlashLight.PreferenceName);
Console.WriteLine(ScannerDefaultFlashLight.Scanner1dCodes);
出力:
ScannerDefaultFlashLight
Scanner1dCodes
他の意見に基づいて、これは私が思いついたものです。このアプローチにより、定数値を取得する場所に.Valueを入力する必要がなくなります。
次のようなすべての文字列列挙の基本クラスがあります。
using System;
using Newtonsoft.Json;
[JsonConverter(typeof(ConstantConverter))]
public class StringEnum: IConvertible
{
public string Value { get; set; }
protected StringEnum(string value)
{
Value = value;
}
public static implicit operator string(StringEnum c)
{
return c.Value;
}
public string ToString(IFormatProvider provider)
{
return Value;
}
public TypeCode GetTypeCode()
{
throw new NotImplementedException();
}
public bool ToBoolean(IFormatProvider provider)
{
throw new NotImplementedException();
}
//The same for all the rest of IConvertible methods
}
JsonConverterは次のようになります。
using System;
using Newtonsoft.Json;
class ConstantConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
serializer.Serialize(writer, null);
}
else
{
serializer.Serialize(writer, value.ToString());
}
}
}
そして実際の文字列列挙は次のようになります:
public sealed class Colors : StringEnum
{
public static Colors Red { get { return new Catalog("Red"); } }
public static Colors Yellow { get { return new Catalog("Yellow"); } }
public static Colors White { get { return new Catalog("White"); } }
private Colors(string value) : base(value) { }
}
これにより、Color.Redを使用して、Valueプロパティを使用せずにjsonにシリアル化することもできます
属性に文字列を格納するような堅牢なものは必要ありませんでした。私はちょうどのようなものを回すのに必要なMyEnum.BillEveryWeek「毎週法案」に、またはMyEnum.UseLegacySystem「使用のレガシーシステム」へ-基本的にindividiual小文字の単語にそのキャメル・ケースで列挙型を分割します。
public static string UnCamelCase(this Enum input, string delimiter = " ", bool preserveCasing = false)
{
var characters = input.ToString().Select((x, i) =>
{
if (i > 0 && char.IsUpper(x))
{
return delimiter + x.ToString(CultureInfo.InvariantCulture);
}
return x.ToString(CultureInfo.InvariantCulture);
});
var result = preserveCasing
? string.Concat(characters)
: string.Concat(characters).ToLower();
var lastComma = result.LastIndexOf(", ", StringComparison.Ordinal);
if (lastComma > -1)
{
result = result.Remove(lastComma, 2).Insert(lastComma, " and ");
}
return result;
}
MyEnum.UseLegacySystem.UnCamelCase() 「レガシーシステムを使用」を出力します
複数のフラグを設定している場合は、それをプレーンな英語に変換します(最後のカンマの代わりに「and」を除いてカンマ区切り)。
var myCustomerBehaviour = MyEnum.BillEveryWeek | MyEnum.UseLegacySystem | MyEnum.ChargeTaxes;
Console.WriteLine(myCustomerBehaviour.UnCamelCase());
//outputs "bill every week, use legacy system and charge taxes"