Wie übergeben Sie mehrere Aufzählungswerte in C #?


117

Manchmal sehe ich beim Lesen des C # -Codes anderer eine Methode, die mehrere Aufzählungswerte in einem einzelnen Parameter akzeptiert. Ich fand es immer ordentlich, habe es aber nie untersucht.

Nun, jetzt denke ich, dass ich vielleicht ein Bedürfnis danach habe, aber ich weiß nicht wie

  1. Richten Sie die Methodensignatur ein, um dies zu akzeptieren
  2. arbeite mit den Werten in der Methode
  3. Definieren Sie die Aufzählung

um so etwas zu erreichen.


In meiner speziellen Situation möchte ich das System.DayOfWeek verwenden, das definiert ist als:

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

Ich möchte einen oder mehrere der DayOfWeek-Werte an meine Methode übergeben können. Kann ich diese bestimmte Aufzählung so verwenden, wie sie ist? Wie mache ich die 3 oben aufgeführten Dinge?


1
Wie unten erwähnt, können Sie eine Flags-Aufzählung verwenden. Vielleicht möchten Sie sich die Vor- und Nachteile von C # -Aufzählungen ansehen , die weitere Informationen zum Arbeiten mit Flags-Aufzählungen enthalten.
ChaseMedallion

Antworten:


181

Wenn Sie die Aufzählung definieren, ordnen Sie sie einfach [Flags] zu, setzen Sie Werte auf Zweierpotenzen, und es funktioniert auf diese Weise.

Es ändert sich nichts anderes, als mehrere Werte an eine Funktion zu übergeben.

Beispielsweise:

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

Weitere Informationen finden Sie in der Dokumentation zu MSDN zu Aufzählungstypen .


Bearbeiten als Antwort auf Ergänzungen zur Frage.

Sie können diese Aufzählung nicht unverändert verwenden, es sei denn, Sie möchten sie beispielsweise als Array / collection / params-Array übergeben. Damit können Sie mehrere Werte übergeben. Die Flags-Syntax erfordert, dass die Aufzählung als Flags angegeben wird (oder dass die Sprache auf eine Weise bastardisiert wird, die nicht entworfen wurde).


9
Ich denke, wenn dies funktionieren soll, müssen die Werte als Zweierpotenzen definiert werden, ein einzelnes Bit für jeden Wert. Was passiert ist, dass Sie das bitweise ODER der Werte im Parameter übergeben, die Sie mit bitweisen UND-Operationen überprüfen können. Wenn Sie sich nicht darum kümmern, die Werte beispielsweise als 1,2,4,8 usw. zu definieren, treten Probleme auf.
Denis Troller

1
Das Festlegen des Flags-Attributs allein funktioniert nicht automatisch. Ich habe es gerade versucht.
Richard Anthony Hein

1
Sie haben Recht, und ich habe die Fehlinformationen entfernt. Reeds Code wurde auch für ihn repariert.
Matthew Scharley

@monoxide: Ich habe es gleichzeitig behoben - Entschuldigung, dass Sie Ihre Änderungen überschrieben haben.
Reed Copsey

2
Kein Problem ... Ich bevorzuge immer noch die Verwendung von Hex für solche Flag-Werte, scheint mir klarer zu sein, aber jeder für sich.
Matthew Scharley

78

Ich denke, die elegantere Lösung ist die Verwendung von 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);
    }

Wenn Sie dies auf diese Weise tun, müssen Sie noch etwas Wichtiges wissen: Es bietet viel mehr Flexibilität, wenn Sie Ihre Aufzählung dynamisch füllen müssen. Beispiel: Wenn Sie Kontrollkästchen verwenden, um die Tage zu definieren, an denen Ihr Programm ausgeführt werden soll, und Sie versuchen würden, dies auf die oben beschriebene Weise zu erreichen, ist der Code nicht lesbar. Also stattdessen können Sie es so machen: ... DaysOfWeek days = new DaysOfWeek(); if (cbTuesday.Checked) days |= DaysOfWeek.Tuesday; if (cbWednesday.Checked) days |= DaysOfWeek.Wednesday;...
CoastN

25

Ich stimme Reeds Antwort zu. Beim Erstellen der Aufzählung müssen Sie jedoch die Werte für jedes Aufzählungselement angeben, damit eine Art Bitfeld entsteht. Beispielsweise:

[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
Dies ist hilfreich, wenn Sie jemals einen DaysOfWeek-Wert überprüfen müssen, z. B. wenn Sie einen Wert lesen, der in einer Datenbank gespeichert ist. Außerdem bietet es anderen Programmierern eine bessere Dokumentation, da einige Wochentage von Montag statt Sonntag beginnen.
Jacob

3
Aus Gründen der Klarheit und Wartbarkeit würde ich Ihre 'All'-Aufzählung als "Sonntag | Montag | Dienstag | Mittwoch | Donnerstag | Freitag | Samstag" schreiben ... und eine ähnliche Notation für' Wochentage 'und' Wochenende 'verwenden.
Robert Cartaino

Dies ist in Ordnung, wenn Sie Ihre eigene Aufzählung erstellen möchten, aber um die Frage zu beantworten, können Sie die vorhandene DaysOfWeek-Aufzählung
Robert Paulson

2
Nicht "vielleicht wollen" ... Sie müssen. Bitweise Vergleiche erfordern es. Wenn Sie die Werte nicht angeben, funktioniert dies nicht.
Richard Anthony Hein

11

In meiner speziellen Situation möchte ich das System.DayOfWeek verwenden

Sie können System.DayOfWeek nicht als [Flags]Aufzählung verwenden, da Sie keine Kontrolle darüber haben. Wenn Sie eine Methode haben möchten, die mehrere akzeptiert, müssen DayOfWeekSie das paramsSchlüsselwort verwenden

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 );

Andernfalls können Sie Ihre eigene [Flags]Aufzählung erstellen, wie von zahlreichen anderen Respondern beschrieben, und bitweise Vergleiche verwenden.


2
Ich weiß nicht, warum ich nicht an Parameter gedacht habe. Dies sollte sehr nützlich sein, um Aufzählungen zu verwenden, die keine Bitfelder sind.
Ronnie Overby

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

Sie müssen die Zahlen angeben und sie wie folgt erhöhen, da die Werte bitweise gespeichert werden.

Definieren Sie dann einfach Ihre Methode, um diese Aufzählung zu erstellen

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

und um es zu nennen, mache so etwas

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

Um zu überprüfen, ob einer der Enum-Werte enthalten war, überprüfen Sie sie mit bitweisen Operationen wie

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

Beantwortet die Frage nicht. "In meiner speziellen Situation möchte ich das System.DayOfWeek verwenden"
Robert Paulson

Aber es ist genau das, wonach ich gesucht habe. Also trotzdem danke.
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
    }

Rufen Sie die Methode in diesem Format auf

MethodName (DaysOfWeek.Tuesday | DaysOfWeek.Thursday);

Implementieren Sie eine EnumToArray-Methode, um die Optionen zu übergeben

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

Beantwortet die Frage nicht. "In meiner speziellen Situation möchte ich das System.DayOfWeek verwenden"
Robert Paulson

Danke, Robert, aber Sie müssen wirklich nicht bei jeder Antwort darauf hinweisen.
Ronnie Overby

@Ronnie - Kaum meine Schuld, dass es so viele nahezu doppelte Antworten gibt, die die Frage nicht wirklich beantwortet haben.
Robert Paulson

@Rony - die Aufzählungen ToString () und Enum.Parse () geben eine [Flags] -Aufzählung korrekt aus / analysieren sie (solange Sie natürlich auf die Versionierung der Aufzählung achten)
Robert Paulson

@ Robert - Ich glaube nicht, dass dich jemand beschuldigt. Lassen Sie einfach die Stimmen sprechen.
Ronnie Overby

3

Markieren Sie Ihre Aufzählung mit dem Attribut [Flags]. Stellen Sie außerdem sicher, dass sich alle Ihre Werte gegenseitig ausschließen (zwei Werte können nicht gleich einem anderen sein), wie z. B. 1,2,4,8,16,32,64 in Ihrem Fall

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

Wenn Sie eine Methode haben, die eine DayOfWeek-Enumeration akzeptiert, verwenden Sie den bitweisen Operator (|), um mehrere Elemente zusammen zu verwenden. Beispielsweise:

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

Um zu überprüfen , ob der Parameter ein bestimmtes Element enthält, verwenden Sie das bitweise und Operator (&) mit dem Element , für den Sie überprüfen.

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

Beantwortet die Frage nicht. "In meiner speziellen Situation möchte ich das System.DayOfWeek verwenden"
Robert Paulson

2

Reed Copsey ist korrekt und ich würde den ursprünglichen Beitrag ergänzen, wenn ich könnte, aber ich kann nicht, also muss ich stattdessen antworten.

Es ist gefährlich, [Flags] nur für eine alte Aufzählung zu verwenden. Ich glaube, Sie müssen die Enum-Werte explizit in Zweierpotenzen ändern, wenn Sie Flags verwenden, um Konflikte in den Werten zu vermeiden. Siehe die Richtlinien für FlagsAttribute und Enum .



-3

Etwas in dieser Art sollte zeigen, wonach Sie suchen:

[Flags]
public enum SomeName
{
    Name1,
    Name2
}

public class SomeClass()
{
    public void SomeMethod(SomeName enumInput)
    {
        ...
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.