次のジェネリック静的メソッドはstringを取り、enumを返します。
うまく大文字と小文字を区別しない ignoreCaseパラメーターをtrueに設定したので。
ただし、列挙型が存在するかどうかをテストするも実行したいのですが、これを行うenum.IsDefinedメソッドにはignoreCaseパラメーターがないようです。
列挙型が定義されているかどうかをテストし、同時にケースを無視するにはどうすればよいですか?
using System;
namespace TestEnum2934234
{
class Program
{
static void Main(string[] args)
{
LessonStatus lessonStatus = StringHelpers.ConvertStringToEnum<LessonStatus>("prepared");
ReportStatus reportStatus = StringHelpers.ConvertStringToEnum<ReportStatus>("finished");
Console.WriteLine(lessonStatus.ToString());
Console.WriteLine(reportStatus.ToString());
Console.ReadLine();
}
}
public static class StringHelpers
{
public static T ConvertStringToEnum<T>(string text)
{
if (Enum.IsDefined(typeof(T), text)) //does not have ignoreCase parameter
return (T)Enum.Parse(typeof(T), text, true);
else
return default(T);
}
}
public enum LessonStatus
{
Defined,
Prepared,
Practiced,
Recorded
}
public enum ReportStatus
{
Draft,
Revising,
Finished
}
}
public enum MyEnum
{
Bar,
Foo
}
class Program
{
static void Main(string[] args)
{
var containsFoo = Enum.GetNames(typeof(MyEnum)).Any(x => x.ToLower() == "foo");
Console.WriteLine(containsFoo);
}
}
@Darinの回答に加えて、.NET 4.0では、Enum型にTryParseメソッドが追加されました。
MyEnum result;
Enum.TryParse("bar", true, out result);
覚えておくべき重要なことは、ParseとTryParseの動作には根本的な違いがあるということです。解析メソッドは例外をスローします。 TryParseメソッドはそうではありません。これは、多くのアイテムを解析しようとしている可能性があるかどうかを知るために非常に重要です。
他の人が言っているように、_Enum.TryParse
_を使用するだけで逃げることができるかもしれません。
ただし、文字列だけでなく変換できる、より堅牢で一般的な変換が必要な場合は、_Enum.IsDefined
_も使用する必要があります。残念ながら、これはnot caseです。 -大文字と小文字を区別しません。
_Enum.TryParse
_ is(可能性があります)大文字と小文字は区別されません。しかし、残念ながら、範囲外のintが通過する可能性があります。
したがって、解決策はそれらを一緒に使用することです(そして順序は重要です)。
私はまさにそれを行う拡張メソッドを書きました。 string、int/int ?、およびその他のEnum/Enum?からの変換が可能です。そのように入力します:
_string value1 = "Value1";
Enum2 enum2 = value1.ParseToEnum<Enum2>();
Debug.Assert(enum2.ToString() == value1);
Enum1 enum1 = Enum1.Value1;
enum2 = enum1.ParseToEnum<Enum2>();
Debug.Assert(enum2.ToString() == enum1.ToString());
int value2 = 1;
enum2 = value2.ParseToEnum<Enum2>();
Debug.Assert(enum2.GetHashCode() == value2);
_
これがメソッドの核心です。これはあなたの質問に答える変換部分です。変数value
はタイプobject
です。これは、メイン入力としてさまざまなタイプを使用する「オーバーロード」があるためです(上記を参照)が、タイプstring
の変数を使用してこれを行うことができます(明らかにvalue.ToString()
をvalue
に変更します)。
_if (value != null)
{
TEnum result;
if (Enum.TryParse(value.ToString(), true, out result))
{
// since an out-of-range int can be cast to TEnum, double-check that result is valid
if (Enum.IsDefined(typeof(TEnum), result.ToString()))
{
return result;
}
}
}
_
私の拡張メソッドにはさらに多くのことがあります...デフォルトを指定でき、範囲外のintを適切に処理し、大文字と小文字を完全に区別しません。興味があればもっと投稿できます。
Compact Framework 3.5を使用していますが、次のようになります。
Enum.TryParse
...存在しません。それは持っています:
Enum.IsDefined
..しかし、それはサポートしていません ignoreCase パラメータ。私は両方の長所が欲しいので、これを(ヘルパーメソッドとして)思いついた...
public bool TryParse<TEnum>(string value, bool ignoreCase, ref TEnum result) where TEnum : struct
{
bool parsed;
try
{
result = (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase);
parsed = true;
}
catch { }
return parsed;
}
HTH
代わりに Enum.TryParse を使用してください:
T val;
if(Enum.TryParse(text, true, out val))
return val;
else
return default(T);
enum DaysCollection
{
sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
public bool isDefined(string[] arr,object obj)
{
bool result=false;
foreach (string enu in arr)
{
result = string.Compare(enu, obj.ToString(), true) == 0;
if (result)
break;
}
return result;
}
private void button1_Click(object sender, EventArgs e)
{
object obj = "wednesday";
string[] arr = Enum.GetNames(typeof(DaysCollection)).ToArray();
isDefined(arr,obj);
}
public static T ConvertStringToEnum<T>(string text)
{
T returnVal;
try
{
returnVal = (T) Enum.Parse( typeof(T), text, true );
}
catch( ArgumentException )
{
returnVal = default(T);
}
return returnVal;
}
同様の懸念があり、.Enum.TryPase
(大文字と小文字を区別しないフラグをtrue
に設定)とEnum.IsDefined
の両方を組み合わせて使用しました。ヘルパークラスを簡略化するものとして、次のことを考慮してください。
public static class StringHelpers
{
public static T ConvertStringToEnum<T>(string text)
{
T result;
return Enum.TryParse(text, true, out result)
&& Enum.IsDefined(result.ToString())
? result
: default(T);
}
}
そして、私たちがそれに取り組んでいる間、ヘルパークラスは静的であり、メソッドは静的であるため、これをstring
の拡張メソッドにすることができます。
public static class StringExtensions
{
public static TEnum ToEnum<TEnum>(this string text)
where TEnum : struct, IComparable, IFormattable, IConvertible
{
TEnum result = default(TEnum);
return !string.IsNullOrWhiteSpace(text)
&& Enum.TryParse(text, true, out result)
&& Enum.IsDefined(typeof(TEnum), result.ToString())
? result
: default(TEnum);
}
}
ここで、私は .NET Fiddle
これは明確にこれを示しています。
テキストを列挙型文字列と同じ大文字小文字にする:
enum FileExts
{
jpg,
pdf
}
if (Enum.IsDefined(typeof(T), text.tolower())) //does not have ignoreCase parameter
return (T)Enum.Parse(typeof(T), text, true);
else
return default(T);
最初にEnum.TryParse
メソッドを使用してタイプT
のオブジェクトを取得し、次にそのオブジェクトをEnum.IsDefined
メソッドに渡します。
private static T ConvertStringToEnum<T>(string stringValue) where T : struct
{
if (System.Enum.TryParse(stringValue, out T result))
{
if (System.Enum.IsDefined(typeof(T), result) || result.ToString().Contains(","))
return result;
throw new System.Exception($"{stringValue} is not an underlying value of the {typeof(T).FullName} enumeration.");
}
throw new System.Exception($"{stringValue} is not a member of the {typeof(T).FullName} enumeration.");
}