tags:

views:

2620

answers:

9

Sometimes when reading others' C# code I see a method that will accept multiple enum values in a single parameter. I always thought it was kind of neat, but never looked into it.

Well, now I think I may have a need for it, but don't know how to

  1. set up the method signature to accept this
  2. work with the values in the method
  3. define the enum

to achieve this sort of thing.


In my particular situation, I would like to use the System.DayOfWeek, which is defined as:

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

I want to be able to pass one or more of the DayOfWeek values to my method. Will I be able to use this particular enum as it is? How do I do the 3 things listed above?

+28  A: 

When you define the enum, just attribute it with [Flags], set values to powers of two, and it will work this way.

Nothing else changes, other than passing multiple values into a function.

For example:

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

For more details, see MSDN's documentation on Enumeration Types.


Edit in response to additions to question.

You won't be able to use that enum as is, unless you wanted to do something like pass it as an array/collection/params array. That would let you pass multiple values. The flags syntax requires the Enum to be specified as flags (or to bastardize the language in a way that's its not designed).

Reed Copsey
WOW...you got that up quick!
Andrew Siemer
I think if you want this to work, the values need to be defined as powers of two, a single bit for each value. What happens is that you pass in the bitwise OR of the values in the parameter, that you can check using bitwise AND operations. If you do not take care of defining the values as, for example, 1,2,4,8 etc, you will have problems.
Denis Troller
Just setting Flags attribute alone doesn't work automatically. I just tried it.
Richard Hein
You're right, and I removed the misinformation. Fixed up Reed's code too for him.
Matthew Scharley
Fixed. I forgot to type that in... thanks
Reed Copsey
@monoxide: I fixed it at the same time - sorry about overriding your edits.
Reed Copsey
No problem... I still prefer using hex for flag values like that, seems more clear to me, but each to his own.
Matthew Scharley
@monoxide: Hex is useful for that, too - especially if you're going to have many elements in your enumerator. Good point. It's a style/personal preference thing, though.
Reed Copsey
A: 

Something of this nature should show what you are looking for:

[Flags]
public enum SomeName
{
    Name1,
    Name2
}

public class SomeClass()
{
    public void SomeMethod(SomeName enumInput)
    {
        ...
    }
}
Andrew Siemer
Won't work without specifying values in powers of 2.
Richard Hein
+1  A: 

I second Reed's answer. However, when creating the enum, you must specify the values for each enum member so it makes a sort of bit field. For example:

[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.
}
Jacob
Why ?
Ronnie Overby
It will help you if you ever need to inspect a DaysOfWeek value, for example if you're reading one that's stored in a database. Also, it provides better documentation to other programmers, since some enumerate days of the week starting from Monday instead of Sunday.
Jacob
For clarity and maintainability, I would write your 'All' enum as "Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday"... and use a similar notation for 'Weekdays' and 'Weekend'.
Robert Cartaino
Good point. That IS better.
Jacob
This is fine if you want to create your own enum, but to answer the question you cannot alter the existing DaysOfWeek enum
Robert Paulson
Not "may want to" ... you MUST. Bitwise comparisons requires it. Leaving the values unspecified will not work.
Richard Hein
+2  A: 
[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
    }

call the method in this format

MethodName(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);

Implement a EnumToArray method to get the options passed

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();
        }
Rony
Interesting but unnecessary.
Richard Hein
Doesn't answer the question. "In my particular situation, I would like to use the System.DayOfWeek"
Robert Paulson
Thanks, Robert, but you really don't have to point this out on every answer.
Ronnie Overby
@Ronnie - Hardly my fault that there are so many near-duplicate answers that didn't actually answer the question.
Robert Paulson
@Rony - the enums ToString() and Enum.Parse() will correctly output / parse a [Flags] enumeration (as long as you're careful of enumeration versioning of course)
Robert Paulson
@Robert - I don't think anyone is blaming you. Just let the votes do the talking.
Ronnie Overby
+3  A: 
[Flags]
public enum DaysOfWeek
{
  Mon = 1,
  Tue = 2,
  Wed = 4,
  Thur = 8,
  Fri = 16,
  Sat = 32,
  Sun = 64
}

You have to specify the numbers, and increment them like this because it is storing the values in a bitwise fashion.

Then just define your method to take this enum

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

and to call it do something like

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

To check if one of the enum values was included check them using bitwise operations like

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
  }
}
Tetraneutron
Doesn't answer the question. "In my particular situation, I would like to use the System.DayOfWeek"
Robert Paulson
+2  A: 

Mark your enum with the [Flags] attribute. Also ensure that all of your values are mutually exclusive (two values can't add up to equal another) like 1,2,4,8,16,32,64 in your case

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

When you have a method that accepts a DayOfWeek enum use the bitwise or operator (|) to use multiple members together. For example:

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

To check if the parameter contains a specific member, use the bitwise and operator (&) with the member you are checking for.

if(arg & DayOfWeek.Sunday == DayOfWeek.Sunday)
Console.WriteLine("Contains Sunday");
statenjason
Doesn't answer the question. "In my particular situation, I would like to use the System.DayOfWeek"
Robert Paulson
+2  A: 

Reed Copsey is correct and I would add to the original post if I could, but I cant so I'll have to reply instead.

Its dangerous to just use [Flags] on any old enum. I believe you have to explicitly change the enum values to powers of two when using flags, to avoid clashes in the values. See the guidelines for FlagsAttribute and Enum.

Dan
A: 

With the help of the posted answers and these:

  1. FlagsAttribute Class (Look at the comparison of using and not using the [Flags] attribute)
  2. Enum Flags Attribute

I feel like I understand it pretty well.

Thanks.

Ronnie Overby
+3  A: 

In my particular situation, I would like to use the System.DayOfWeek

You can not use the System.DayOfWeek as a [Flags] enumeration because you have no control over it. If you wish to have a method that accepts multiple DayOfWeek then you will have to use the params keyword

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

Otherwise you can create your own [Flags] enumeration as outlined by numerous other responders and use bitwise comparisons.

Robert Paulson
I don't know why I didn't think of params. That should be very useful for using enums that aren't bitfields.
Ronnie Overby