web-dev-qa-db-ja.com

C#で複数の列挙値をどのように渡しますか?

他の人のC#コードを読み取るときに、1つのパラメーターで複数の列挙値を受け入れるメソッドが表示されることがあります。私はいつもそれがちょっときちんとしたものだと思っていましたが、決して調べませんでした。

まあ、今私はそれを必要とするかもしれないと思うが、どのように

  1. これを受け入れるようにメソッドシグネチャを設定します
  2. メソッドの値を操作する
  3. 列挙型を定義する

この種のことを達成するために。


[Serializable]
[ComVisible(true)]
public enum DayOfWeek
{ 
    Sunday = 0,   
    Monday = 1,   
    Tuesday = 2,   
    Wednesday = 3,   
    Thursday = 4,   
    Friday = 5,    
    Saturday = 6
}

1つ以上のDayOfWeek値をメソッドに渡すことができるようにしたい。この特定の列挙型をそのまま使用できますか?上記の3つのことを行うにはどうすればよいですか?

110
Ronnie Overby

列挙型を定義する場合、[Flags]で列挙し、値を2のべき乗に設定するだけで、このように機能します。

関数に複数の値を渡すこと以外は何も変わりません。

例えば:

[Flags]
enum DaysOfWeek
{
   Sunday = 1,
   Monday = 2,
   Tuesday = 4,
   Wednesday = 8,
   Thursday = 16,
   Friday = 32,
   Saturday = 64
}

public void RunOnDays(DaysOfWeek days)
{
   bool isTuesdaySet = (days & DaysOfWeek.Tuesday) == DaysOfWeek.Tuesday;

   if (isTuesdaySet)
      //...
   // Do your work here..
}

public void CallMethodWithTuesdayAndThursday()
{
    this.RunOnDays(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);
}

詳細については、 列挙型に関するMSDNのドキュメント を参照してください。


質問への追加に応じて編集します。

Array/collection/params配列として渡すようなことをしたくない限り、その列挙型をそのまま使用することはできません。これにより、複数の値を渡すことができます。 flags構文では、Enumをフラグとして指定する必要があります(または、設計されていない方法で言語をろくでなしにする)。

168
Reed Copsey

よりエレガントなソリューションは、HasFlag()を使用することだと思います。

    [Flags]
    public enum DaysOfWeek
    {
        Sunday = 1,
        Monday = 2,
        Tuesday = 4,
        Wednesday = 8,
        Thursday = 16,
        Friday = 32,
        Saturday = 64
    }

    public void RunOnDays(DaysOfWeek days)
    {
        bool isTuesdaySet = days.HasFlag(DaysOfWeek.Tuesday);

        if (isTuesdaySet)
        {
            //...
        }
    }

    public void CallMethodWithTuesdayAndThursday()
    {
        RunOnDays(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);
    }
75
Tillito

リードの答えをもう1つ。ただし、列挙型を作成するときは、各列挙型メンバーの値を指定して、ビットフィールドのようなものを作成する必要があります。例えば:

[Flags]
public enum DaysOfWeek
{
    Sunday = 1,
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thursday = 16,
    Friday = 32,
    Saturday = 64,

    None = 0,
    All = Weekdays | Weekend,
    Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday,
    Weekend = Sunday | Saturday,
    // etc.
}
23
Jacob

私の特定の状況では、System.DayOfWeekを使用したいと思います

System.DayOfWeekを制御できないため、[Flags]列挙として使用できません。複数のDayOfWeekを受け入れるメソッドが必要な場合は、paramsキーワードを使用する必要があります。

void SetDays(params DayOfWeek[] daysToSet)
{
    if (daysToSet == null || !daysToSet.Any())
        throw new ArgumentNullException("daysToSet");

    foreach (DayOfWeek day in daysToSet)
    {
        // if( day == DayOfWeek.Monday ) etc ....
    }
}

SetDays( DayOfWeek.Monday, DayOfWeek.Sunday );

それ以外の場合は、他の多数のレスポンダーによって概説されているように、独自の[Flags]列挙を作成し、ビットごとの比較を使用できます。

11
Robert Paulson
[Flags]
public enum DaysOfWeek
{
  Mon = 1,
  Tue = 2,
  Wed = 4,
  Thur = 8,
  Fri = 16,
  Sat = 32,
  Sun = 64
}

数値を指定し、ビット単位で値を格納しているため、このように増分する必要があります。

次に、この列挙型を取るようにメソッドを定義するだけです

public void DoSomething(DaysOfWeek day)
{
  ...
}

そしてそれを呼び出すには

DoSomething(DaysOfWeek.Mon | DaysOfWeek.Tue) // Both Monday and Tuesday

列挙値のいずれかが含まれているかどうかを確認するには、次のようなビット演算を使用してそれらを確認します

public void DoSomething(DaysOfWeek day)
{
  if ((day & DaysOfWeek.Mon) == DaysOfWeek.Mon) // Does a bitwise and then compares it to Mondays enum value
  {
    // Monday was passed in
  }
}
9
Tetraneutron
[Flags]
    public enum DaysOfWeek{


        Sunday = 1 << 0,
        Monday = 1 << 1,
        Tuesday = 1 << 2,
        Wednesday = 1 << 3,
        Thursday = 1 << 4,
        Friday =  1 << 5,
        Saturday =  1 << 6
    }

この形式でメソッドを呼び出す

MethodName(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);

EnumToArrayメソッドを実装して、渡されたオプションを取得します

private static void AddEntryToList(DaysOfWeek days, DaysOfWeek match, List<string> dayList, string entryText) {
            if ((days& match) != 0) {
                dayList.Add(entryText);
            }
        }

        internal static string[] EnumToArray(DaysOfWeek days) {
            List<string> verbList = new List<string>();

            AddEntryToList(days, HttpVerbs.Sunday, dayList, "Sunday");
            AddEntryToList(days, HttpVerbs.Monday , dayList, "Monday ");
            ...

            return dayList.ToArray();
        }
3
Rony

[Flags]属性で列挙型をマークします。また、1,2,4,8,16,32,64のように、すべての値が相互に排他的であることを確認します(2つの値を合計して別の値に等しくすることはできません)

[Flags]
public enum DayOfWeek
{ 
Sunday = 1,   
Monday = 2,   
Tuesday = 4,   
Wednesday = 8,   
Thursday = 16,   
Friday = 32,    
Saturday = 64
}

DayOfWeek列挙型を受け入れるメソッドがある場合、ビットごとのOR演算子(|)を使用して、複数のメンバーを一緒に使用します。例えば:

MyMethod(DayOfWeek.Sunday|DayOfWeek.Tuesday|DayOfWeek.Friday)

パラメーターに特定のメンバーが含まれているかどうかを確認するには、チェックするメンバーにビット単位のand演算子(&)を使用します。

if(arg & DayOfWeek.Sunday == DayOfWeek.Sunday)
Console.WriteLine("Contains Sunday");
3
statenjason

Reed Copseyは正解で、できれば元の投稿に追加しますが、できませんので、代わりに返信する必要があります。

古い列挙型で[フラグ]を使用するのは危険です。値の衝突を避けるために、フラグを使用する場合、enum値を明示的に2のべき乗に変更する必要があると思います。 FlagsAttributeおよびEnumのガイドライン を参照してください。

2
Dan

投稿された回答とこれらの助けを借りて:

  1. FlagsAttribute Class ([Flags]属性を使用する場合と使用しない場合の比較をご覧ください)
  2. 列挙フラグ属性

私はそれをかなりよく理解しているように感じます。

ありがとう。

0
Ronnie Overby