9

C# での列挙型の楽しみ。以前に定義したいくつかの Enum を格納するために作成された汎用リストを 1 つ取り、そこにいくつかの項目を追加します。foreach で反復GetEnumerator<T>()するか、元の列挙型以外の列挙型を指定して、何が起こるかを確認します。InvalidCastException またはそのようなものを期待していましたが、完全に機能します:)。

例として、単純なコンソール アプリケーションを使用して、Cars と Animals という 2 つの列挙型を作成してみましょう。

    public enum Cars
    {
        Honda = 0,
        Toyota = 1,
        Chevrolet = 2
    }
    public enum Animals
    {
        Dog = 0,
        Cat = 1,
        Tiger = 2
    }

そして、メインメソッドでこれを行います:

    public static void Main()
    {
        List<Cars> cars = new List<Cars>();
        List<Animals> animals = new List<Animals>();
        cars.Add(Cars.Chevrolet);
        cars.Add(Cars.Honda);
        cars.Add(Cars.Toyota);

        foreach (Animals isItACar in cars)
        {
            Console.WriteLine(isItACar.ToString());
        }
        Console.ReadLine();
    }

これをコンソールに出力します:

Tiger
Dog
Cat

なぜこうなった?私の最初の推測では、enum 自体は実際には Type ではなく、単なる int ですが、そうではありません。

Console.WriteLine(Animals.Tiger.GetType().FullName); 彼の完全修飾名を印刷します! では、なぜこれが?

4

3 に答える 3

21

列挙型は異なりますが、foreach にある暗黙のキャストによって混乱しています。

ループを少し書き直してみましょう。

public static void Main()
{
    List<Cars> cars = new List<Cars>();
    List<Animals> animals = new List<Animals>();
    cars.Add(Cars.Chevrolet);
    cars.Add(Cars.Honda);
    cars.Add(Cars.Toyota);

    foreach (Cars value in cars)
    {
        // This time the cast is explicit.
        Animals isItACar = (Animals) value;
        Console.WriteLine(isItACar.ToString());
    }
    Console.ReadLine();
}

結果はあなたを驚かせますか?ある列挙型から別の列挙型にキャストできるという事実を除いて、そうでないことを願っています。これは、元のコードが行っていることのより明示的なバージョンです。

foreachすべてのループに (通常はノーオペレーションであるにもかかわらず)暗黙のキャストがあるという事実は、ほとんどの開発者が混乱を招くと思います。

C# 3.0 仕様のセクション 8.8.4 から:

上記の手順が成功すると、コレクションの型 C、列挙子の型 E、および要素の型 T が明確に生成されます。次の形式の foreach ステートメント

foreach (V v in x)  embedded-statement 

その後、次のように展開されます。

{
    E e = ((C)(x)).GetEnumerator();
    try {
        V v;
        while (e.MoveNext()) {
            v = (V)(T)e.Current;
            embedded-statement
        }
    }
    finally {
        ... // Dispose e
    }
}

列挙変換自体は、セクション 6.2.2 で説明されています。

明示的な列挙変換は次のとおりです。

  • sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、または decimal から任意の列挙型まで。
  • 任意の列挙型から、sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、または decimal まで。
  • 任意の列挙型から他の列挙型へ。

2 つの型の間の明示的な列挙型変換は、関与する列挙型をその列挙型の基になる型として扱い、結果の型の間で暗黙的または明示的な数値変換を実行することによって処理されます。たとえば、基になる型が int の列挙型 E が与えられた場合、E から byte への変換は int から byte への明示的な数値変換 (§6.2.1) として処理され、byte から E への変換は次のように処理されます。 byte から int への暗黙の数値変換 (§6.1.2)。

于 2008-12-09T09:21:59.790 に答える
2

概念的には、Enum は文字列表現と数値を持つ静的に型指定された値です。列挙型を呼び出すとToString()、文字列表現が返されます。列挙型を呼び出すとGetType()、静的列挙型が取得されます。列挙型を にキャストすると、列挙int型の整数値が得られます。

列挙型は厳密に型指定されているはずですが、対応する宣言がなくても任意の整数を任意の列挙型にキャストできるという事実など、注意する必要があることがいくつかあります (この場合、文字列表現は番号と同じです)。

CLR では、列挙型 ( bools など) は単に s として扱われintますが、GetType() または GetString() を呼び出すと、上記で説明したことを行うバージョンが呼び出されます。

于 2008-12-09T09:13:59.383 に答える
0

特定のタイプから列挙型を導出することもできます。

public enum Cats : byte { ... }
public enum Dogs : int { ... }
于 2008-12-09T16:36:02.393 に答える