[C#] 列挙型を反復処理するにはどうすればよいですか?



Answers

値よりむしろ、それぞれの列挙型の名前を実際に印刷したいと思うように見えます。 Enum.GetNames()は正しいアプローチのようです。

public enum Suits
{
    Spades,
    Hearts,
    Clubs,
    Diamonds,
    NumSuits
}

public void PrintAllSuits()
{
    foreach (string name in Enum.GetNames(typeof(Suits)))
    {
        System.Console.WriteLine(name);
    }
}

ちなみに、値をインクリメントすることは、列挙型の値を列挙する良い方法ではありません。 代わりにこれを行う必要があります。

代わりにEnum.GetValues(typeof(Suit))使用します。

public enum Suits
{
    Spades,
    Hearts,
    Clubs,
    Diamonds,
    NumSuits
}

public void PrintAllSuits()
{
    foreach (var suit in Enum.GetValues(typeof(Suits)))
    {
        System.Console.WriteLine(suit.ToString());
    }
}
Question

どのようにC#でenumを列挙できますか?

たとえば、次のコードはコンパイルされません。

public enum Suit 
{
    Spades,
    Hearts,
    Clubs,
    Diamonds
}

public void EnumerateAllSuitsDemoMethod() 
{
    foreach (Suit suit in Suit) 
    {
        DoSomething(suit);
    }
}

また、次のコンパイル時エラーが発生します。

「スーツ」は「タイプ」ですが、「変数」のように使用されます

2番目のキーワードであるSuitキーワードでは失敗します。




ここでは、DDLの選択オプションを作成する作業例を示します

var resman = ViewModelResources.TimeFrame.ResourceManager;

ViewBag.TimeFrames = from MapOverlayTimeFrames timeFrame 
      in Enum.GetValues(typeof(MapOverlayTimeFrames))
      select new SelectListItem
      {
         Value = timeFrame.ToString(),
         Text = resman.GetString(timeFrame.ToString()) ?? timeFrame.ToString()
      };



この質問は、「 C#Step by Step 2013 」の第10章にあります。

著者は、二重for-loopを使用して一対の列挙子を反復して(カードのフルデッキを作成する):

class Pack
{
    public const int NumSuits = 4;
    public const int CardsPerSuit = 13;
    private PlayingCard[,] cardPack;

    public Pack()
    {
        this.cardPack = new PlayingCard[NumSuits, CardsPerSuit];
        for (Suit suit = Suit.Clubs; suit <= Suit.Spades; suit++)
        {
            for (Value value = Value.Two; value <= Value.Ace; value++)
            {
                cardPack[(int)suit, (int)value] = new PlayingCard(suit, value);
            }
        }
    }
}

この場合、 SuitValueは両方とも列挙型です:

enum Suit { Clubs, Diamonds, Hearts, Spades }
enum Value { Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace}

PlayingCardは、 SuitValue定義されたカードオブジェクトです。

class PlayingCard
{
    private readonly Suit suit;
    private readonly Value value;

    public PlayingCard(Suit s, Value v)
    {
        this.suit = s;
        this.value = v;
    }
}



Cast<T>を使用しているのはなぜですか?

var suits = Enum.GetValues(typeof(Suit)).Cast<Suit>();

そこにIEnumerable<Suit>があります。




メソッドをpublic static IEnumerable<T> GetValues<T>()をクラスに追加します。

public static IEnumerable<T> GetValues<T>()
{
    return Enum.GetValues(typeof(T)).Cast<T>();
}

あなたの列挙型を呼び出して渡してください。これでforeachを使ってiterateできます

 public static void EnumerateAllSuitsDemoMethod()
 {
     // custom method
     var foos = GetValues<Suit>(); 
     foreach (var foo in foos)
     {
         // Do something
     }
 }



列挙型を相互作用できるものに変換する簡単で一般的な方法:

public static Dictionary<int, string> ToList<T>() where T : struct
{
   return ((IEnumerable<T>)Enum
       .GetValues(typeof(T)))
       .ToDictionary(
           item => Convert.ToInt32(item),
           item => item.ToString());
}

その後:

var enums = EnumHelper.ToList<MyEnum>();



私は、これがより良い、あるいは良いという意見を持っていない、ただ別の解決策を述べている。

enum値の範囲が厳密に0からn - 1の場合、一般的な代替方法は次のとおりです。

public void EnumerateEnum<T>()
{
    int length = Enum.GetValues(typeof(T)).Length;
    for (var i = 0; i < length; i++)
    {
        var @enum = (T)(object)i;
    }
}

enum値が連続していて、enumの最初と最後の要素を指定できる場合は、次のようにします。

public void EnumerateEnum()
{
    for (var i = Suit.Spade; i <= Suit.Diamond; i++)
    {
        var @enum = i;
    }
}

それは厳密に列挙しているわけではなく、ただループしているだけです。 2番目の方法は他の方法よりもはるかに高速です...




.NET Frameworkの一部のバージョンでは、 Enum.GetValuesサポートしていません。 Ideas 2.0の優れた回避策は次のとおりです。Compact FrameworkのEnum.GetValues

public List<Enum> GetValues(Enum enumeration)
{
   List<Enum> enumerations = new List<Enum>();
   foreach (FieldInfo fieldInfo in enumeration.GetType().GetFields(
         BindingFlags.Static | BindingFlags.Public))
   {
      enumerations.Add((Enum)fieldInfo.GetValue(enumeration));
   }
   return enumerations;
}

reflectionを含むコードと同様に、一度しか実行されず、結果がキャッシュされるようにするための手順を実行する必要があります。




私は2つのペンスを投げつけるでしょう。ちょうど私が一番簡単な拡張子

public static class EnumExtensions
{
    /// <summary>
    /// Gets all items for an enum value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public static IEnumerable<T> GetAllItems<T>(this Enum value)
    {
        return (T[])Enum.GetValues(typeof (T));
    }
}

きれいなシンプルで、@ Jeppe-Stig-Nielsenのコメントは速い。




enum型は "列挙型"と呼ばれます。なぜなら、値を列挙するコンテナではなく、その型の変数に可能な値を列挙して定義するためです。

(実際にはそれよりも少し複雑です - 列挙型は "基底"の整数型を持つと見なされます。つまり、各列挙型の値は整数値に対応します(これは暗黙的ですが、手動で指定できます)。あなたが "名前"の値でなくても、その型の任意の整数をenum変数に入れることができるようにします。

System.Enum.GetNamesメソッドを使用すると、名前が示すように、列挙型の名前である文字列の配列を取得できます。

編集:代わりにSystem.Enum.GetValuesメソッドを提案している必要がありSystem.Enum.GetValues 。 おっとっと。




コンパクトなフレームワーク(3.5)で動作し、コンパイル時に型チェックサポートする私のソリューションを追加するだけです:

public static List<T> GetEnumValues<T>() where T : new() {
    T valueType = new T();
    return typeof(T).GetFields()
        .Select(fieldInfo => (T)fieldInfo.GetValue(valueType))
        .Distinct()
        .ToList();
}

public static List<String> GetEnumNames<T>() {
    return typeof (T).GetFields()
        .Select(info => info.Name)
        .Distinct()
        .ToList();
}

- 誰かがT valueType = new T()を取り除く方法を知っているなら、私は解決策を見てうれしいです。

コールは次のようになります。

List<MyEnum> result = Utils.GetEnumValues<MyEnum>();



public void PrintAllSuits()
{
    foreach(string suit in Enum.GetNames(typeof(Suits)))
    {
        Console.WriteLine(suit);
    }
}



私はToString()を使用して、フラグ内でspit配列を分割して解析します。

[Flags]
public enum ABC {
   a = 1,
   b = 2,
   c = 4
};

public IEnumerable<ABC> Getselected (ABC flags)
{
   var values = flags.ToString().Split(',');
   var enums = values.Select(x => (ABC)Enum.Parse(typeof(ABC), x.Trim()));
   return enums;
}

ABC temp= ABC.a | ABC.b;
var list = getSelected (temp);
foreach (var item in list)
{
   Console.WriteLine(item.ToString() + " ID=" + (int)item);
}



Links