C#でどのようint
にキャストできますか?enum
32 に答える
int から:
YourEnum foo = (YourEnum)yourInt;
文字列から:
YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString);
// The foo.ToString().Contains(",") check is necessary for enumerations marked with an [Flags] attribute
if (!Enum.IsDefined(typeof(YourEnum), foo) && !foo.ToString().Contains(","))
{
throw new InvalidOperationException($"{yourString} is not an underlying value of the YourEnum enumeration.")
}
アップデート:
番号からもできます
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
キャストするだけです:
MyEnum e = (MyEnum)3;
Enum.IsDefinedを使用して範囲内にあるかどうかを確認できます。
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
または、ワンライナーの代わりに拡張メソッドを使用します。
public static T ToEnum<T>(this string enumString)
{
return (T) Enum.Parse(typeof (T), enumString);
}
使用法:
Color colorEnum = "Red".ToEnum<Color>();
また
string color = "Red";
var colorEnum = color.ToEnum<Color>();
完全な答えを得るには、列挙型が .NET の内部でどのように機能するかを知る必要があると思います。
仕組み
.NET の列挙型は、一連の値 (フィールド) を基本型 (デフォルトはint
) にマップする構造です。ただし、実際には、列挙型がマップする整数型を選択できます。
public enum Foo : short
この場合、列挙型はshort
データ型にマップされます。つまり、列挙型は short としてメモリに格納され、キャストして使用すると short として動作します。
IL の観点から見ると、(通常の int) 列挙型は次のようになります。
.class public auto ansi serializable sealed BarFlag extends System.Enum
{
.custom instance void System.FlagsAttribute::.ctor()
.custom instance void ComVisibleAttribute::.ctor(bool) = { bool(true) }
.field public static literal valuetype BarFlag AllFlags = int32(0x3fff)
.field public static literal valuetype BarFlag Foo1 = int32(1)
.field public static literal valuetype BarFlag Foo2 = int32(0x2000)
// and so on for all flags or enum values
.field public specialname rtspecialname int32 value__
}
ここで注目すべきは、value__
が列挙値とは別に保存されていることです。上記の列挙Foo
型の場合、型value__
は int16 です。これは基本的に、型が一致する限り、列挙型に何でも格納できることを意味します。
System.Enum
この時点で、これが値型であることを指摘したいと思います。これは基本的BarFlag
に、メモリ内で 4 バイトを使用し、Foo
2 を使用することを意味します。たとえば、基になる型のサイズです (実際にはそれよりも複雑ですが、おい...)。
答え
したがって、列挙型にマップしたい整数がある場合、ランタイムは 2 つのことだけを行う必要があります。4 バイトをコピーして、別の名前 (列挙型の名前) を付けます。データは値型として保存されるため、コピーは暗黙的です。これは基本的に、アンマネージ コードを使用する場合、データをコピーせずに単に列挙型と整数を交換できることを意味します。
安全にするために、基になる型が同じか暗黙的に変換可能であることを確認し、列挙型の値が存在することを確認するのがベスト プラクティスだと思います(既定ではチェックされません!)。
これがどのように機能するかを確認するには、次のコードを試してください。
public enum MyEnum : int
{
Foo = 1,
Bar = 2,
Mek = 5
}
static void Main(string[] args)
{
var e1 = (MyEnum)5;
var e2 = (MyEnum)6;
Console.WriteLine("{0} {1}", e1, e2);
Console.ReadLine();
}
へのキャストe2
も機能することに注意してください。上記のコンパイラの観点から、これは理にかなっています。value__
フィールドは単純に 5 または 6 で埋められ、 をConsole.WriteLine
呼び出すとToString()
、 の名前e1
は解決されますが、 の名前は解決されe2
ません。
Enum.IsDefined(typeof(MyEnum), 6)
それが意図したものではない場合は、キャストしている値が定義済みの列挙型にマップされているかどうかを確認するために使用します。
また、コンパイラが実際にこれをチェックしているにもかかわらず、列挙型の基になる型について明示していることにも注意してください。これは、途中で予期せぬ事態に遭遇しないようにするためです。これらの驚きの動作を確認するには、次のコードを使用できます (実際、データベース コードでこれが頻繁に発生するのを見てきました)。
public enum MyEnum : short
{
Mek = 5
}
static void Main(string[] args)
{
var e1 = (MyEnum)32769; // will not compile, out of bounds for a short
object o = 5;
var e2 = (MyEnum)o; // will throw at runtime, because o is of type int
Console.WriteLine("{0} {1}", e1, e2);
Console.ReadLine();
}
次の例を見てください。
int one = 1;
MyEnum e = (MyEnum)one;
このコードを使用して、int を列挙型にキャストしています。
if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }
私はそれが最善の解決策だと思います。
以下は列挙型の便利なユーティリティ クラスです。
public static class EnumHelper
{
public static int[] ToIntArray<T>(T[] value)
{
int[] result = new int[value.Length];
for (int i = 0; i < value.Length; i++)
result[i] = Convert.ToInt32(value[i]);
return result;
}
public static T[] FromIntArray<T>(int[] value)
{
T[] result = new T[value.Length];
for (int i = 0; i < value.Length; i++)
result[i] = (T)Enum.ToObject(typeof(T),value[i]);
return result;
}
internal static T Parse<T>(string value, T defaultValue)
{
if (Enum.IsDefined(typeof(T), value))
return (T) Enum.Parse(typeof (T), value);
int num;
if(int.TryParse(value,out num))
{
if (Enum.IsDefined(typeof(T), num))
return (T)Enum.ToObject(typeof(T), num);
}
return defaultValue;
}
}
数値の場合、何があってもオブジェクトを返すため、これはより安全です。
public static class EnumEx
{
static public bool TryConvert<T>(int value, out T result)
{
result = default(T);
bool success = Enum.IsDefined(typeof(T), value);
if (success)
{
result = (T)Enum.ToObject(typeof(T), value);
}
return success;
}
}
4.0 .NET Frameworkの準備ができている場合は、非常に便利で [Flags] 属性とうまく連携する新しいEnum.TryParse()関数があります。Enum.TryParse メソッド (文字列、TEnum%)を参照してください。
型にオブジェクトがある場合がありますMyEnum
。お気に入り
var MyEnumType = typeof(MyEnum);
それで:
Enum.ToObject(typeof(MyEnum), 3)
ビットマスクとして機能し、[Flags]列挙で1つ以上の値を表すことができる整数がある場合は、このコードを使用して、個々のフラグ値をリストに解析できます。
for (var flagIterator = 0; flagIterator < 32; flagIterator++)
{
// Determine the bit value (1,2,4,...,Int32.MinValue)
int bitValue = 1 << flagIterator;
// Check to see if the current flag exists in the bit mask
if ((intValue & bitValue) != 0)
{
// If the current flag exists in the enumeration, then we can add that value to the list
// if the enumeration has that flag defined
if (Enum.IsDefined(typeof(MyEnum), bitValue))
Console.WriteLine((MyEnum)bitValue);
}
}
enum
これは、の基になる型が符号付き32ビット整数であることを前提としていることに注意してください。別の数値タイプの場合は、ハードコードされた32を変更して、そのタイプのビットを反映する必要があります(または、を使用してプログラムで導出する必要がありますEnum.GetUnderlyingType()
) 。
これは、フラグ列挙型の安全な変換メソッドです。
public static bool TryConvertToEnum<T>(this int instance, out T result)
where T: Enum
{
var enumType = typeof (T);
var success = Enum.IsDefined(enumType, instance);
if (success)
{
result = (T)Enum.ToObject(enumType, instance);
}
else
{
result = default(T);
}
return success;
}
文字列を ENUM に、または int を ENUM 定数に変換するには、Enum.Parse 関数を使用する必要があります。これは実際に文字列を使用したデモを行うYouTubeビデオhttps://www.youtube.com/watch?v=4nhx4VwdRDk であり、同じことがintにも当てはまります。
コードは次のようになります。ここで、「red」は文字列で、「MyColors」は色定数を持つ色 ENUM です。
MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");
以下は、わずかに優れた拡張方法です。
public static string ToEnumString<TEnum>(this int enumValue)
{
var enumString = enumValue.ToString();
if (Enum.IsDefined(typeof(TEnum), enumValue))
{
enumString = ((TEnum) Enum.ToObject(typeof (TEnum), enumValue)).ToString();
}
return enumString;
}
これは、 Tawani のユーティリティ クラスのようなジェネリックを使用して、.NET 4.0 の部分一致で整数または文字列をターゲット列挙型に解析します。不完全なコマンドラインスイッチ変数を変換するために使用しています。列挙型を null にすることはできないため、デフォルト値を論理的に指定する必要があります。次のように呼び出すことができます。
var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);
コードは次のとおりです。
using System;
public class EnumParser<T> where T : struct
{
public static T Parse(int toParse, T defaultVal)
{
return Parse(toParse + "", defaultVal);
}
public static T Parse(string toParse, T defaultVal)
{
T enumVal = defaultVal;
if (defaultVal is Enum && !String.IsNullOrEmpty(toParse))
{
int index;
if (int.TryParse(toParse, out index))
{
Enum.TryParse(index + "", out enumVal);
}
else
{
if (!Enum.TryParse<T>(toParse + "", true, out enumVal))
{
MatchPartialName(toParse, ref enumVal);
}
}
}
return enumVal;
}
public static void MatchPartialName(string toParse, ref T enumVal)
{
foreach (string member in enumVal.GetType().GetEnumNames())
{
if (member.ToLower().Contains(toParse.ToLower()))
{
if (Enum.TryParse<T>(member + "", out enumVal))
{
break;
}
}
}
}
}
参考までに: 質問は整数に関するもので、誰も言及していませんが、Enum.TryParse()でも明示的に変換されます
Int32
にキャストする拡張メソッドを次に示しEnum
ます。
値が可能な最大値よりも高い場合でも、ビットごとのフラグを尊重します。たとえば、可能性が1、2、および4の列挙型があるが、int が9である場合、8がない場合は1として理解されます。これにより、コードを更新する前にデータを更新できます。
public static TEnum ToEnum<TEnum>(this int val) where TEnum : struct, IComparable, IFormattable, IConvertible
{
if (!typeof(TEnum).IsEnum)
{
return default(TEnum);
}
if (Enum.IsDefined(typeof(TEnum), val))
{//if a straightforward single value, return that
return (TEnum)Enum.ToObject(typeof(TEnum), val);
}
var candidates = Enum
.GetValues(typeof(TEnum))
.Cast<int>()
.ToList();
var isBitwise = candidates
.Select((n, i) => {
if (i < 2) return n == 0 || n == 1;
return n / 2 == candidates[i - 1];
})
.All(y => y);
var maxPossible = candidates.Sum();
if (
Enum.TryParse(val.ToString(), out TEnum asEnum)
&& (val <= maxPossible || !isBitwise)
){//if it can be parsed as a bitwise enum with multiple flags,
//or is not bitwise, return the result of TryParse
return asEnum;
}
//If the value is higher than all possible combinations,
//remove the high imaginary values not accounted for in the enum
var excess = Enumerable
.Range(0, 32)
.Select(n => (int)Math.Pow(2, n))
.Where(n => n <= val && n > 0 && !candidates.Contains(n))
.Sum();
return Enum.TryParse((val - excess).ToString(), out asEnum) ? asEnum : default(TEnum);
}
入力データをユーザーが希望するenumに変換するのに役立ちます。以下のような列挙型があり、デフォルトでintがあるとします。列挙型の最初にデフォルト値を追加してください。入力値との一致が見つからない場合にヘルパー メソッドで使用されます。
public enum FriendType
{
Default,
Audio,
Video,
Image
}
public static class EnumHelper<T>
{
public static T ConvertToEnum(dynamic value)
{
var result = default(T);
var tempType = 0;
//see Note below
if (value != null &&
int.TryParse(value.ToString(), out tempType) &&
Enum.IsDefined(typeof(T), tempType))
{
result = (T)Enum.ToObject(typeof(T), tempType);
}
return result;
}
}
NB:ここでは、値を int に解析しようとします。これは、enum がデフォルトでintであるためです。バイト型 であるこのように enum を定義する場合。
public enum MediaType : byte
{
Default,
Audio,
Video,
Image
}
ヘルパーメソッドでの解析をから変更する必要があります
int.TryParse(value.ToString(), out tempType)
に
byte.TryParse(value.ToString(), out tempType)
次の入力の方法を確認します
EnumHelper<FriendType>.ConvertToEnum(null);
EnumHelper<FriendType>.ConvertToEnum("");
EnumHelper<FriendType>.ConvertToEnum("-1");
EnumHelper<FriendType>.ConvertToEnum("6");
EnumHelper<FriendType>.ConvertToEnum("");
EnumHelper<FriendType>.ConvertToEnum("2");
EnumHelper<FriendType>.ConvertToEnum(-1);
EnumHelper<FriendType>.ConvertToEnum(0);
EnumHelper<FriendType>.ConvertToEnum(1);
EnumHelper<FriendType>.ConvertToEnum(9);
私の英語でごめんなさい
キャストするさまざまな方法 Enum
enum orientation : byte
{
north = 1,
south = 2,
east = 3,
west = 4
}
class Program
{
static void Main(string[] args)
{
orientation myDirection = orientation.north;
Console.WriteLine(“myDirection = {0}”, myDirection); //output myDirection =north
Console.WriteLine((byte)myDirection); //output 1
string strDir = Convert.ToString(myDirection);
Console.WriteLine(strDir); //output north
string myString = “north”; //to convert string to Enum
myDirection = (orientation)Enum.Parse(typeof(orientation),myString);
}
}
以下のようにするだけです:
int intToCast = 1;
TargetEnum f = (TargetEnum) intToCast ;
正しい値のみをキャストし、それ以外の場合は例外をスローできることを確認するには:
int intToCast = 1;
if (Enum.IsDefined(typeof(TargetEnum), intToCast ))
{
TargetEnum target = (TargetEnum)intToCast ;
}
else
{
// Throw your exception.
}
IsDefined の使用はコストがかかり、キャストするだけではないことに注意してください。そのため、使用するかどうかは実装に依存します。
シンプルに int を列挙型にキャストできます
public enum DaysOfWeeks
{
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6,
Sunday = 7,
}
var day= (DaysOfWeeks)5;
Console.WriteLine("Day is : {0}", day);
Console.ReadLine();