C#で複数の列挙値を渡すにはどうすればよいですか?


117

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

さて、私はそれが必要だと思うかもしれませんが、方法がわかりません

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

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


私の特定の状況では、次のように定義されているSystem.DayOfWeekを使用したいと思います。

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

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


1
後述するように、Flags列挙型を使用できます。Flags列挙型の操作に関する詳細情報が含まれているC#列挙型のインとアウトを確認することをお勧めします
ChaseMedallion 2014

回答:


181

列挙型を定義するときは、それを[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配列として渡したい場合を除いて、この列挙型をそのまま使用することはできません。これにより、複数の値を渡すことができます。フラグ構文では、Enumをフラグとして指定する必要があります(または、設計されていない方法で言語を粗末化する必要があります)。


9
これを機能させるには、値を2の累乗、つまり各値の1ビットとして定義する必要があると思います。何が起こるかというと、パラメーターの値のビットORを渡し、ビットAND演算を使用して確認できるということです。たとえば、1、2、4、8などのように値を定義しないと、問題が発生します。
Denis Troller

1
Flags属性だけを設定しても、自動的には機能しません。試してみたところです。
Richard Anthony Hein、

1
あなたは正しい、そして私は誤った情報を削除した。リードのコードも修正しました。
Matthew Scharley、2009年

@一酸化炭素:同時に修正しました-編集内容を上書きしてしまい申し訳ありません。
リードコプシー、

2
問題ありません...私はまだそのようなフラグ値に16進数を使用することを好みます。
マシュー・シャーリー09/06/23

78

よりエレガントな解決策は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);
    }

このようにすると、もう1つ知っておくべき重要なことがあります。それは、列挙型を動的に埋める必要がある場合に、はるかに高い柔軟性を追加します。例:チェックボックスを使用してプログラムを実行する曜日を定義し、上記の方法でこれを達成しようとすると、コードが読み取れなくなります。したがって、代わりに次のように行うことができます。... DaysOfWeek days = new DaysOfWeek(); if (cbTuesday.Checked) days |= DaysOfWeek.Tuesday; if (cbWednesday.Checked) days |= DaysOfWeek.Wednesday;...
CoastN

25

私はリードの答えの2番目です。ただし、列挙型を作成するときは、列挙型メンバーごとに値を指定して、一種のビットフィールドを作成する必要があります。例えば:

[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.
}

1
データベースに保存されている値を読み取る場合など、DaysOfWeek値を検査する必要がある場合に役立ちます。また、日曜日ではなく月曜日から始まる曜日を列挙するものもあるので、他のプログラマーにより良いドキュメントを提供します。
ジェイコブ

3
わかりやすく、保守しやすいように、「すべて」の列挙型を「日曜日|月曜日|火曜日|水曜日|木曜日|金曜日|土曜日」と記述し、同様に「平日」と「週末」の表記を使用します。
Robert Cartaino 2009年

独自の列挙型を作成したい場合はこれで問題ありませんが、質問に答えるために既存のDaysOfWeek列挙型を変更することはできません
Robert Paulson

2
「したいかもしれない」ではない...あなたは必ずしなければならない。ビットごとの比較にはそれが必要です。値を指定しないままにすると機能しません。
リチャードアンソニーハイン

11

私の特定の状況では、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]は、他の多数のレスポンダで概説されている独自の列挙を作成し、ビットごとの比較を使用できます。


2
なぜパラメータを考えなかったのか分かりません。これは、ビットフィールドではない列挙型を使用する場合に非常に役立ちます。
ロニーオーバーバイ

10
[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

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

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
  }
}

質問には答えません。「私の特定の状況では、System.DayOfWeekを使用したい」
Robert Paulson

しかし、それはまさに私が探していたものです。とにかくありがとう。
Tillito

3
[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();
        }

質問には答えません。「私の特定の状況では、System.DayOfWeekを使用したい」
ロバートポールソン

ありがとう、ロバート。しかし、すべての回答でこれを指摘する必要はありません。
ロニーオーバーバイ

@ロニー-実際に質問に答えなかった重複に近い答えがたくさんあるというのは、ほとんど私のせいではありません。
ロバートポールソン

@Rony-列挙型ToString()およびEnum.Parse()は、[Flags]列挙型を正しく出力/解析します(もちろん、列挙型のバージョン管理に注意している限り)
Robert Paulson

@ロバート-誰かがあなたを責めているとは思わない。投票で話をさせてください。
ロニーオーバーバイ

3

enumに[Flags]属性を付けます。また、すべての値が相互に排他的であることを確認してください(2つの値を合計しても、互いに等しくすることはできません)。たとえば、1、2、4、8、16、32、64などです。

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

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

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

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

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

質問には答えません。「私の特定の状況では、System.DayOfWeekを使用したい」
Robert Paulson

2

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

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



-3

この性質の何かはあなたが探しているものを示すはずです:

[Flags]
public enum SomeName
{
    Name1,
    Name2
}

public class SomeClass()
{
    public void SomeMethod(SomeName enumInput)
    {
        ...
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.