如何在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
}

我希望能够将一个或多个DayOfWeek值传递给我的方法。我可以按原样使用此特定枚举吗?我该如何做上面列出的三件事?


1
如下所述,您可以使用Flags枚举。您可能想查看C#枚举的来龙去脉,其中包含有关使用Flags枚举的更多信息。
ChaseMedallion 2014年

Answers:


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文档


编辑以回答问题。

您将无法按原样使用该枚举,除非您想执行将其作为数组/集合/参数数组传递的操作。那将使您传递多个值。标志语法要求将Enum指定为标志(或以非设计的方式对语言进行混用)。


9
我认为,如果您希望此方法有效,则需要将值定义为2的幂,每个值用一位。发生的情况是您传入了参数中值的按位“或”,可以使用按位“与”操作进行检查。如果您不注意将值定义为1,2,4,8等,则会遇到问题。
Denis Troller 2009年

1
仅设置Flags属性不会自动工作。我刚试过
理查德·安东尼·海因

1
您说得对,我删除了错误信息。也为他修复了里德的代码。
马修·沙利

@monoxide:我同时修复了它-很抱歉覆盖您的修改。
Reed Copsey

2
没问题...我仍然更喜欢将十六进制用于这样的标志值,对我来说似乎更清楚,但每个都针对自己。
马修·沙尔利

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

如果您这样做,还需要知道另一件事:当您需要动态填充枚举时,它将增加更多的灵活性。例如:如果您使用复选框定义希望程序运行的日期,并且您将尝试以上面的方式完成此操作,则代码将不可读。因此,您可以这样操作:... DaysOfWeek days = new DaysOfWeek(); if (cbTuesday.Checked) days |= DaysOfWeek.Tuesday; if (cbWednesday.Checked) days |= DaysOfWeek.Wednesday;...
CoastN

25

我第二次回答里德。但是,在创建枚举时,必须为每个枚举成员指定值,以便它成为一种位字段。例如:

[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
为清楚起见和可维护性,我将您的“全部”枚举写为“周日|星期一|周二|周三|周四|星期五|星期六” ...并对“周日”和“周末”使用类似的符号。
罗伯特·卡塔诺

如果您想创建自己的枚举,这很好,但是要回答这个问题,您不能更改现有的DaysOfWeek枚举
Robert Paulson 2009年

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

要检查是否包含枚举值之一,请使用按位操作(例如

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 2011年

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”
Robert Paulson

谢谢,罗伯特,但您实际上不必在每个答案中都指出这一点。
罗尼·奥弗比

@Ronnie-几乎没有我的错,实际上有这么多重复的答案并没有真正回答问题。
罗伯特·保尔森

@Rony-枚举ToString()和Enum.Parse()将正确输出/解析[Flags]枚举(只要您当然注意枚举版本控制)
罗伯特·保尔森

@Robert-我想没有人在怪你。只是让选票说话。
罗尼·奥弗比

3

用[Flags]属性标记您的枚举。还要确保所有值都是互斥的(两个值的和不能等于另一个值),例如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)
    {
        ...
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.