2

从客户端我得到一个列表,其中每个 int 值是 Enum DayOfWeek 的枚举 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 的幂。

4

5 回答 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);

更新

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

var output = input.Select(i => (DayOfWeek)Math.Pow(2, (i - 1) % 7)).ToList();
于 2013-03-22T22:33:21.470 回答
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,
}

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

于 2013-03-22T22:29:45.383 回答
0

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

(2) 对于每个 DayValue,设置

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

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

于 2013-03-22T22:28:08.473 回答
0

你可以这样做:

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

编辑:我可能把你的问题弄错了,我以为你得到了一个整数列表并想将它们转换为 DayOfWeek。如果你只想要一整天,你可以做(DayOfWeek)127或只是添加AllDays = 127到枚举中。

于 2013-03-22T22:28:41.537 回答
0

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

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

例如,您可能有一个 C 程序需要跟踪一堆不同的正交条件(我们将它们称为 Condition0、Condition1、Condition2 等......)但是为了节省空间,或者更容易传递这些条件作为一个单元,我们希望将它们全部压缩成一个 8 位(或更大)的值。然后你要做的是定义这样的条件:

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

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

因此,我们可以结合这两个列表并看到:

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

如果我们需要表示 Condition1 和 Condition2 已经发生,那么这意味着设置了位 1 和位 2。二进制是 0b0110,十进制是“6”。表示 Condition1 和 Condition2 的值只是 Condition1 和 Condition2 的逻辑或。0b0010 或 0b0110 是 0b0110。2 或 4 是 6。

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

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

  • 然后将其与表示“条件0 和条件1”已设置的值结合起来。0b0011 或十进制的“3”

  • 如果您执行逻辑 OR - (0b0110 OR 0b0011),您将得到 0b0111 或十进制 7。这看起来像“Condition0、Condition1 和 Condition2”都是正确的。这似乎是正确的!

但是,如果将值相加,则会得到十进制 9(6 + 3,或 0b0110 + 0b0011),即 0b1001。0b1001 看起来像“条件 3 为真,条件 0 为真”,这是不对的。Condition3 是如何参与其中的,Condition1 和 Condition2 发生了什么?当我们开始时,它们都设置好了!

现在,回到 C# 世界——“标志”属性的意思是“这个枚举可以由一个或多个可以独立存在或不存在的正交条件组成”。程序员可以为枚举的不同元素分配值,以使它们不重叠(就像在 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 指南建议不要这样做的注释。

于 2013-03-22T23:04:02.987 回答