2011-02-03 2 views
4

文字列型の数値を対応する列挙型に変換しています。コードをテストしている間、私は混乱している面白い動作を発見しました。Enumの解析との混同

以下のコード例を使用して、「s」変数にEnum値の1つと一致しない値がある場合に、例外がスローされない理由を明らかにすることができますか?また、sEnum varをStooge enumの定義内に存在しない値に設定する方法はありますか?

class Program 
{ 
    enum Stooge 
    { 
     Unspecified, 
     Moe, 
     Larry, 
     Curly, 
     Shemp 
    } 

    static void Main(string[] args) 
    { 
     while (true) 
     { 
      Console.WriteLine("Enter a number..."); 

      string s = Console.ReadLine(); 
      Stooge sEnum = (Stooge)(int.Parse(s)); //Why doesn't this line throw if s != 0, 1, 2, 3, or 4? 

      Console.WriteLine("\r\nYou entered: {0}\r\nEnum String Value: {1}\r\nEnum Int Value: {2}\r\n", s, sEnum.ToString(), (int)sEnum); 
     } 
    } 
} 
+0

[なぜ無効な列挙値にキャストintは例外をスローしないのですか?](http://stackoverflow.com/questions/6413804/why-does-casting-int-to-invalid-enum-value-not -throw-exception) – nawfal

答えて

7

これは.NETを作成した人の一部の決定でした。列挙型は別の値型(int,short,byteなど)によってサポートされているため、これらの値型に対して実際に有効な任意の値を持つことができます。

は、私は個人的にこれが機能する方法のファンではないので、私はユーティリティメソッドの一連の作っ:

/// <summary> 
/// Utility methods for enum values. This static type will fail to initialize 
/// (throwing a <see cref="TypeInitializationException"/>) if 
/// you try to provide a value that is not an enum. 
/// </summary> 
/// <typeparam name="T">An enum type. </typeparam> 
public static class EnumUtil<T> 
    where T : struct, IConvertible // Try to get as much of a static check as we can. 
{ 
    // The .NET framework doesn't provide a compile-checked 
    // way to ensure that a type is an enum, so we have to check when the type 
    // is statically invoked. 
    static EnumUtil() 
    { 
     // Throw Exception on static initialization if the given type isn't an enum. 
     Require.That(typeof (T).IsEnum,() => typeof(T).FullName + " is not an enum type."); 
    } 

    /// <summary> 
    /// In the .NET Framework, objects can be cast to enum values which are not 
    /// defined for their type. This method provides a simple fail-fast check 
    /// that the enum value is defined, and creates a cast at the same time. 
    /// Cast the given value as the given enum type. 
    /// Throw an exception if the value is not defined for the given enum type. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="enumValue"></param> 
    /// <exception cref="InvalidCastException"> 
    /// If the given value is not a defined value of the enum type. 
    /// </exception> 
    /// <returns></returns> 
    public static T DefinedCast(object enumValue) 

    { 
     if (!System.Enum.IsDefined(typeof(T), enumValue)) 
      throw new InvalidCastException(enumValue + " is not a defined value for enum type " + 
              typeof (T).FullName); 
     return (T) enumValue; 
    } 

    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="enumValue"></param> 
    /// <returns></returns> 
    public static T Parse(string enumValue) 
    { 
     var parsedValue = (T)System.Enum.Parse(typeof (T), enumValue); 
     //Require that the parsed value is defined 
     Require.That(parsedValue.IsDefined(), 
      () => new ArgumentException(string.Format("{0} is not a defined value for enum type {1}", 
       enumValue, typeof(T).FullName))); 
     return parsedValue; 
    } 

    public static bool IsDefined(T enumValue) 
    { 
     return System.Enum.IsDefined(typeof (T), enumValue); 
    } 

} 

public static class EnumExtensions 
{ 
    public static bool IsDefined<T>(this T enumValue) 
     where T : struct, IConvertible 
    { 
     return EnumUtil<T>.IsDefined(enumValue); 
    } 
} 

この方法では、私が言うことができます。

if(!sEnum.IsDefined()) throw new Exception(...); 

を...か:

+0

'Require.That'はまた、私自身のライブラリから来ています。あなたはそれを 'if(!...)と置き換えることができます。新しい例外をスローする(...); – StriplingWarrior

+0

私はRequire.Thatが好きです。 –

+1

@kirsteng:それは非常に簡単です:https://gist.github.com/j2jensen/11377210 – StriplingWarrior

2

enumは技術的にint(または、enumの基になる型を定義したもの)です。 Enum.IsDefinedを呼び出しても、列挙の対応する値を確認できます。詳細はこちら:Cast int to enum in C#

1

Enumは、int以上の本当に薄いラッパーです。基本的にはint +可能な値の静的なコレクション(定数の並べ替え)です。すべてのチェックはコンパイル時、型チェックなどにありますが、実際にintenumランタイムにキャストしても問題ありません。あなたの入力を検証してください!

-1

渡された値が解析できない場合に例外がスローされないようにするには、int.Parse()を使用します。例外がスローされることなく無効である可能性のある値を解析したくない場合は、int.TryParse()を使用します。

+1

これは彼がやっていることではない。有効なint値であるかどうかにかかわらず、値がenum型の定義された値でない場合、例外がスローされます。 – StriplingWarrior

関連する問題