Come si passano più valori enum in C #?


117

A volte, durante la lettura del codice C # di altri, vedo un metodo che accetta più valori enum in un singolo parametro. Ho sempre pensato che fosse abbastanza carino, ma non l'ho mai esaminato.

Bene, ora penso di averne bisogno, ma non so come farlo

  1. impostare la firma del metodo per accettarlo
  2. lavorare con i valori nel metodo
  3. definire l'enumerazione

per ottenere questo genere di cose.


Nella mia situazione particolare, vorrei utilizzare System.DayOfWeek, che è definito come:

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

Voglio essere in grado di trasferire uno o più valori DayOfWeek al mio metodo. Potrò usare questo particolare enum così com'è? Come faccio le 3 cose sopra elencate?


1
Come accennato di seguito, puoi usare un'enumerazione Flags. Potresti voler controllare i dettagli delle enumerazioni C # , che contengono ulteriori informazioni sull'utilizzo delle enumerazioni Flags.
ChaseMedallion

Risposte:


181

Quando definisci l'enumerazione, attribuiscilo con [Flags], imposta i valori a potenze di due e funzionerà in questo modo.

Nient'altro cambia, a parte il passaggio di più valori in una funzione.

Per esempio:

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

Per ulteriori dettagli, vedere la documentazione di MSDN sui tipi di enumerazione .


Modifica in risposta alle aggiunte alla domanda.

Non sarai in grado di usare quell'enumerazione così com'è, a meno che tu non voglia fare qualcosa come passarlo come array / collection / params. Ciò ti consentirebbe di trasmettere più valori. La sintassi dei flag richiede che Enum sia specificato come flag (o per imbastardizzare il linguaggio in un modo che non è stato progettato).


9
Penso che se vuoi che funzioni, i valori devono essere definiti come potenze di due, un singolo bit per ogni valore. Quello che succede è che passi l'OR bit per bit dei valori nel parametro, che puoi controllare utilizzando operazioni AND bit per bit. Se non ti occupi di definire i valori come, ad esempio, 1,2,4,8 ecc., Avrai problemi.
Denis Troller

1
L'impostazione dell'attributo Flags da sola non funziona automaticamente. L'ho appena provato.
Richard Anthony Hein,

1
Hai ragione e ho rimosso la disinformazione. Risolto anche il problema con il codice di Reed.
Matthew Scharley,

@ monossido: l'ho corretto allo stesso tempo, mi dispiace per aver ignorato le tue modifiche
Reed Copsey,

2
Nessun problema ... io preferisco ancora usare hex per valori di flag come quello, mi sembra più chiaro, ma ciascuno per il suo.
Matthew Scharley,

78

Penso che la soluzione più elegante sia usare 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);
    }

C'è un'altra cosa importante da sapere, se lo fai in questo modo: aggiunge molta più flessibilità quando devi riempire dinamicamente la tua enum. Ad esempio: se utilizzi le caselle di controllo per definire i giorni in cui desideri che il tuo programma venga eseguito, e provi a farlo nel modo in cui è stato fatto sopra, il codice sarà illeggibile. Quindi invece puoi farlo in questo modo: ... DaysOfWeek days = new DaysOfWeek(); if (cbTuesday.Checked) days |= DaysOfWeek.Tuesday; if (cbWednesday.Checked) days |= DaysOfWeek.Wednesday;...
CoastN

25

Secondo la risposta di Reed. Tuttavia, quando si crea l'enumerazione, è necessario specificare i valori per ogni membro dell'enumerazione in modo che crei una sorta di campo di bit. Per esempio:

[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
Ti aiuterà se mai avrai bisogno di ispezionare un valore DaysOfWeek, ad esempio se stai leggendo uno che è memorizzato in un database. Inoltre, fornisce una migliore documentazione ad altri programmatori, poiché alcuni enumerano i giorni della settimana a partire dal lunedì invece che dalla domenica.
Jacob,

3
Per chiarezza e manutenibilità, scriverei l'enumerazione "Tutti" come "Domenica | Lunedì | Martedì | Mercoledì | Giovedì | Venerdì | Sabato" ... e utilizzare una notazione simile per "Giorni feriali" e "Fine settimana".
Robert Cartaino

Questo va bene se vuoi creare la tua enumerazione, ma per rispondere alla domanda non puoi alterare l'enumerazione DaysOfWeek esistente
Robert Paulson,

2
Non "potresti volerlo" ... DEVI. I confronti bit per bit lo richiedono. Lasciando i valori non specificati non funzionerà.
Richard Anthony Hein,

11

Nella mia situazione particolare, vorrei utilizzare System.DayOfWeek

Non è possibile utilizzare System.DayOfWeek come [Flags]enumerazione perché non si ha alcun controllo su di esso. Se desideri avere un metodo che accetta più, DayOfWeekdovrai utilizzare la paramsparola chiave

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

Altrimenti puoi creare la tua [Flags]enumerazione come delineato da numerosi altri risponditori e utilizzare confronti bit per bit.


2
Non so perché non ho pensato ai params. Questo dovrebbe essere molto utile per usare enumerazioni che non sono bitfield.
Ronnie Overby,

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

Devi specificare i numeri e incrementarli in questo modo perché memorizza i valori in modo bit per bit.

Quindi definisci il tuo metodo per prendere questo enum

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

e per chiamarlo fai qualcosa di simile

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

Per verificare se uno dei valori enum è stato incluso, controllali usando operazioni bit per bit come

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

Non risponde alla domanda. "Nella mia situazione particolare, vorrei utilizzare System.DayOfWeek"
Robert Paulson,

Ma e 'esattamente quello che stavo cercando. Quindi grazie comunque.
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
    }

chiama il metodo in questo formato

MethodName (DaysOfWeek.Tuesday | DaysOfWeek.Th Thursday);

Implementa un metodo EnumToArray per far passare le opzioni

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

Non risponde alla domanda. "Nella mia situazione particolare, vorrei utilizzare System.DayOfWeek"
Robert Paulson,

Grazie, Robert, ma davvero non devi farlo notare in ogni risposta.
Ronnie Overby,

@Ronnie - Non è colpa mia se ci sono così tante risposte quasi duplicate che in realtà non hanno risposto alla domanda.
Robert Paulson,

@Rony - le enumerazioni ToString () e Enum.Parse () produrranno / analizzeranno correttamente un'enumerazione [Flags] (a patto che tu stia attento al controllo delle versioni dell'enumerazione, ovviamente)
Robert Paulson,

@Robert - Non credo che nessuno ti stia incolpando. Lascia che siano i voti a parlare.
Ronnie Overby,

3

Contrassegna la tua enumerazione con l'attributo [Flags]. Assicurati inoltre che tutti i tuoi valori si escludano a vicenda (due valori non possono sommarsi per essere uguali a un altro) come 1,2,4,8,16,32,64 nel tuo caso

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

Quando si dispone di un metodo che accetta un'enumerazione DayOfWeek, utilizzare l'operatore bit per bit o (|) per utilizzare più membri insieme. Per esempio:

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

Per verificare se il parametro contiene un membro specifico, utilizzare l' operatore bit per bit e (&) con il membro che si sta verificando.

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

Non risponde alla domanda. "Nella mia situazione particolare, vorrei utilizzare System.DayOfWeek"
Robert Paulson,

2

Reed Copsey ha ragione e vorrei aggiungere al post originale se potessi, ma non posso quindi dovrò rispondere invece.

È pericoloso usare solo [Flags] su qualsiasi vecchia enumerazione. Credo che sia necessario modificare esplicitamente i valori enum in potenze di due quando si usano i flag, per evitare conflitti nei valori. Vedere le linee guida per FlagsAttribute ed Enum .



-3

Qualcosa di questa natura dovrebbe mostrare quello che stai cercando:

[Flags]
public enum SomeName
{
    Name1,
    Name2
}

public class SomeClass()
{
    public void SomeMethod(SomeName enumInput)
    {
        ...
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.