首页 文章

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

提问于
浏览
2

从客户端我得到一个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,
}

UPDATE

这是来自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 回答

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

    Update

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

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

    像这样:

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

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

  • 0

    你可以这样做:

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

    编辑:我可能错了你的问题,我认为你得到一个整数列表,并希望将它们转换为DayOfWeek . 如果你只想要所有的日子,你可以做 (DayOfWeek)127 或只是添加 AllDays = 127 枚举 .

  • 1

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

    (2)对于每个DayValue,设置

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

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

  • 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,
    

    In Conclusion: 对标志求和仅适用于某些情况(主要是当每个被求和的值表示单个条件时) . 为了编写在所有情况下都能正常工作的健壮代码,您应该坚持使用标志的逻辑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;
    

    现在,你将've thrown an extra wrinkle in the works by not making 2801505 0, but I' ll作为一项练习留给作为练习的读者添加了注释MSDN guidelines建议不要这样做 .

相关问题