将多个列表枚举值写入另一个枚举

时间:2013-03-22 22:23:42

标签: c# enums flags enum-flags

从客户端我得到一个List,其中每个int值是Enum DayOfWeek的enum int值。

该列表仅包含在时间规划器中可见的int值(天)。

获取int值列表,例如0,1,2(星期日,星期一,星期二)你会如何以一般方式将这些价值观写入DayOfWeek枚举7天或没有一天工作?

只知道星期六的索引为6,而我的DayOfWeek枚举值为32。

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

更新

这是来自MarcinJuraszek的工作解决方案代码,它只是改变了我的需求:

var visibleWeekDays = new List<int>();
            for (int i = 0; i <= 6; i++)
            {
                visibleWeekDays.Add(i);
            }

            int allBitValues = visibleWeekDays.Select(i => (int)Math.Pow(2, ((i + 6) % 7))).Aggregate((e, i) => e | i);
            AllVisibleDays = (VisibleDayOfWeek) allBitValues;


[Flags]
public enum VisibleDayOfWeek
{
    None = 0,
    Mon = 1, 
    Tue = 2,
    Wed = 4,
    Thu = 8,
    Fri = 16,
    Sat = 32,
    Sun = 64
}


 public VisibleDayOfWeek AllVisibleDays { get; set; }

上面的代码将一周中的所有日子写入VisibleDayOfWeek枚举,现在可以轻松保存在数据库字段中。

根据Microsoft MSDN,标志枚举的None值现在再次设置为0,其余值为2的幂。

5 个答案:

答案 0 :(得分:3)

var input = new List<int>() { 0, 1, 2 };

var output = input.Select(i => (DayOfWeek)Math.Pow(2, ((i + 6) % 7))).ToList();

奇怪的((i + 6) % 7)是必要的,因为标准DayOfWeek从星期日开始,而你的64作为星期日的值。

您也可以使用LINQ将标志聚合为单个int值:

var x = output.Select(i => (int)i).Aggregate((e, i) => e | i);

<强>更新

对于已更改的标记,您必须更改翻译查询:

var output = input.Select(i => (DayOfWeek)Math.Pow(2, (i - 1) % 7)).ToList();

答案 1 :(得分:1)

像这样:

private void button1_Click(object sender, EventArgs e)
{
    var mylist = new List<int>() { 0, 1, 2 }; // Sunday, Monday, Tuesday

    DayOfWeek days = (DayOfWeek)0;
    foreach (var item in mylist)
        days |= (DayOfWeek)Math.Pow(2, item);

    Debug.WriteLine(days);
    // Displays "Sunday, Monday, Tuesday"
}
[Flags]
public enum DayOfWeek
{
    None = 0,
    Sunday = 1,
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thursday = 16,
    Friday = 32,
    Saturday = 64,
}

(编辑以匹配编辑过的问题)

答案 2 :(得分:0)

(1)将Undefined的名称更改为None;这更符合语义。

(2)对于每个DayValue,设置

dayOfWeek |= (DayOfWeek) Math.Pow(2,DayValue);

DayValue是输入值:0,1,...,6

答案 3 :(得分:0)

你可以这样做:

var days = (DayOfWeek)listOfValues.Sum();

编辑:我可能错了你的问题,我认为你得到一个整数列表,并希望将它们转换为DayOfWeek。如果您只需要所有日期,则可以执行(DayOfWeek)127或仅将AllDays = 127添加到枚举。

答案 4 :(得分:0)

理解这个问题的答案需要更深入地了解枚举类的[Flags]属性。您可以阅读有关此属性的信息(或阅读有关如何使用它的一些指导原则)here at MSDN

“Flags”属性是C世界的遗留物,你没有C#和CLR给你的所有花哨类型。

例如,你可能有一个C程序需要跟踪一堆不同的正交条件(我们称之为Condition0,Condition1,Condition2等......)但是为了节省空间,或者让它更容易通过这些条件作为一个单元,我们希望将它们全部塞入一个8位(或更大)值。那么你要做的是定义条件:

  • 位0跟踪Condition0的状态
  • 位1跟踪Condition1的状态
  • 位2跟踪Condition2的状态

如果你还记得二进制到十进制的转换,你就会知道   - 位0表示十进制值1   - 位1表示小数值2   - 位2表示小数值4   - 位4表示小数值8   - 位n代表n的幂的小数值2

因此,我们可以将这两个列表结合起来,看看:

  • Condition0的值为1(4位二进制为0b0001)
  • Condition1的值为2(4位二进制为0b0010)
  • Condition2的值为4(4位二进制中为0b0100)
  • 等。 。

如果我们需要表示发生了Condition1和Condition2,则表示设置了位1和位2。在二进制中,它是0b0110,在十进制中是“6”。表示Condition1和Condition2的值只是Condition1和Condition2的逻辑OR。 0b0010或0b0110是0b0110。 2或4是6。

现在,你可能已经注意到逻辑OR和Condition1和Condition2的总和在上面的例子中出现了相同的值(2 + 4 = 2 OR 4)。 “我知道,我只是将所有条件加在一起!”你会说。编写List.Sum()比使用OR和累加器的for循环更容易。不幸的是,这不会一直有效。

  • 再次考虑上面的“6”或0b0110的值,这意味着“Condition1和Condition2”为真。

  • 然后将其与设置为“Condition0和Condition1”的值组合。 0b0011或十进制“3”

  • 如果您执行逻辑OR - (0b0110 OR 0b0011),则会得到0b0111或小数7.这看起来像“Condition0,Condition1和Condition2”都是真的。这似乎是正确的!

如果你将这些值加在一起,你会得到十进制9(6 + 3,或0b0110 + 0b0011),它出现在0b1001。 0b1001看起来像“条件3是真的,条件0是真的”这不可能是正确的。 Condition3如何参与此处以及Condition1和Condition2发生了什么?当我们开始时它们都被设定了!

现在,回到C#世界 - “Flags”属性意味着“此枚举可以由一个或多个可以存在或不存在的正交条件组成”。程序员可以自己为枚举的不同元素赋值,使它们不重叠(就像在C中一样)。一旦完成,您可以通过对它们执行逻辑OR运算来愉快地组合这些正交条件中的一个或多个。您甚至可以在枚举中定义元素,这些元素是先前定义的元素的组合。考虑元素

Weekends = Saturday | Sunday,
Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday,

结论: 对标志求和仅适用于某些情况(主要是当每个被求和的值表示单个条件时)。为了编写在所有情况下都能正常工作的健壮代码,您应该坚持使用标志的逻辑OR。可能需要额外的几行来编写,但它更准确地捕获您的意图,更容易维护,并且如果有人将您不期望的内容传递到您的方法中,则会更加强大。因此,要组合列表中的所有元素,您应该将它们全部组合在一起。像

这样的东西
FlagsEnum accumulator = 0; //Or better yet, FlagsEnum accumulator = FlagsEnum.None if you've followed the design guidelines
foreach(FlagsEnum flag in ListOfflags)
{
  accumulator |= flag;
}
return accumulator;

现在,你已经因为没有“无”0而在作品中引起了额外的皱纹,但是我会把这个作为练习留给读者,附加说明MSDN guidelines建议不要做这一点。