简体   繁体   English

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

[英]Write multiple list enum values into another enum

From the client I get a List where each int value is the enum int value of the Enum DayOfWeek. 从客户端,我得到一个列表,其中每个int值是Enum DayOfWeek的枚举int值。

The list contains only those int values (days) which are visible in a time planner. 该列表仅包含在计划程序中可见的int值(天)。

Taking the list of int values eg 0,1,2 (sunday,monday,tuesday) how would you write those values into the DayOfWeek enum in a general way working for all 7 days or no day? 以int值列表为例,例如0,1,2(星期天,星期一,星期二),您将如何以通常的方式将这些值写到DayOfWeek枚举中,从而连续7天或全天不工作?

Just know that the Saturday has an index of 6 while my DayOfWeek enum has 32 as value. 只知道星期六的索引为6,而我的DayOfWeek枚举的索引值为32。

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

UPDATE UPDATE

This is the working solution code from MarcinJuraszek which is just changed to my needs: 这是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; }

The above code writes all days of a week into the VisibleDayOfWeek enum which could be easily saved now in a database field. 上面的代码将一周中的所有天都写入VisibleDayOfWeek枚举,现在可以轻松地将其保存在数据库字段中。

According to Microsoft MSDN the flag enum has its None value now set to 0 again and the rest values are the power of 2. 根据Microsoft MSDN,标志枚举将其None值现在再次设置为0,其余值为2的幂。

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

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

That strange ((i + 6) % 7) is necessary because standard DayOfWeek starts from Sunday, and yours has 64 as a value for Sunday. 因为标准的DayOfWeek从星期日开始,而您的周日值为64 ,所以这个奇怪的((i + 6) % 7)是必需的。

You can use LINQ also to aggregate flags into single int value: 您还可以使用LINQ将标志聚合为单个int值:

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

Update 更新

For changed flags you have to change translation query: 对于更改的标志,您必须更改翻译查询:

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

Like this: 像这样:

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

(Edited to match the edited question) (已编辑以匹配已编辑的问题)

(1) Change the name of Undefined to None; (1)将Undefined的名称更改为None; this fits the semantics better. 这更适合语义。

(2) For every DayValue, set (2)对于每个DayValue,设置

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

DayValue is the input vale coming in: 0,1, ..., 6 DayValue是输入值:0,1,...,6

You could do something like this: 您可以执行以下操作:

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

Edit: I might have gotten your question wrong, i thought you get a list of integers and want to convert those to DayOfWeek. 编辑:我可能已经把你的问题弄错了,我以为你会得到一个整数列表,并想将它们转换为DayOfWeek。 If you want just all days, you could do (DayOfWeek)127 or just add AllDays = 127 to the enum. 如果只想整天,您可以执行(DayOfWeek)127或仅将AllDays = 127添加到枚举。

Understanding the answer to this question requires a deeper understanding of the [Flags] attribute on your enum class. 要了解该问题的答案,需要对您的枚举类的[Flags]属性有更深入的了解。 You can read about this attribute (or read some guidelines about how to use it) here at MSDN 您可以在MSDN上阅读有关此属性的信息(或阅读有关使用此属性的一些准则)

The "Flags" attribute is kind of a left-over from the C world where you didn't have all of the fancy types that C# and the CLR give you. “标志”属性是C世界中的一种遗留物,在这里您没有C#和CLR给您的所有奇特类型。

For example, you could have a C program that needs to track a bunch of different orthogonal conditions (we'll call them Condition0, Condition1, Condition2 etc. . .) but to save space, or to make it easier to pass these conditions around as a single unit, we want to jam them all into one 8-bit (or larger) value. 例如,您可能有一个C程序,该程序需要跟踪一堆不同的正交条件(我们将它们称为Condition0,Condition1,Condition2等..),但可以节省空间,也可以使其更容易传递这些条件作为一个单元,我们希望将它们全部塞入一个8位(或更大)的值。 What you would do then is define the conditions such that: 然后,您要做的就是定义条件,使得:

  • Bit 0 tracks the state of Condition0 位0跟踪Condition0的状态
  • Bit 1 tracks the state of Condition1 位1跟踪Condition1的状态
  • Bit 2 tracks the state of Condition2 位2跟踪Condition2的状态
  • etc. 等等

If you remember your binary-to-decimal conversions, you'll know that - Bit 0 represents a decimal value of 1 - Bit 1 represents a decimal value of 2 - Bit 2 represents a decimal value of 4 - Bit 4 represents a decimal value of 8 - Bit n represents a decimal value of 2 to the power of n 如果您还记得二进制到十进制的转换,您将知道-位0代表十进制值1-位1代表十进制值2-位2代表十进制值4-位4代表十进制值的8-位n代表2的十进制值乘以n的幂

Therefore, we can combine those two lists and see that: 因此,我们可以合并这两个列表,然后看到:

  • Condition0 has a value of 1 (0b0001 in 4-bit binary) Condition0的值为1(4位二进制为0b0001)
  • Condition1 has a value of 2 (0b0010 in 4-bit binary) Condition1的值为2(4位二进制为0b0010)
  • Condition2 has a value of 4 (0b0100 in 4-bit binary) Condition2的值为4(4位二进制为0b0100)
  • etc. . 等。 .

If we need to represents that Condition1 and Condition2 have occurred, then that would mean bits 1 and bits 2 are set. 如果我们需要表示已发生Condition1和Condition2,则意味着设置了位1和位2。 In binary, that's 0b0110 and in decimal that's "6". 二进制形式为0b0110,十进制形式为“ 6”。 A value that represents Condition1 and Condition2 is simply the logical OR of Condition1 and Condition2. 表示Condition1和Condition2的值只是Condition1和Condition2的逻辑或。 0b0010 OR 0b0110 is 0b0110. 0b0010或0b0110为0b0110。 2 OR 4 is 6. 2 OR 4是6

Now, you may have noticed that a logical OR and the sum of Condition1 and Condition2 come out to the same value in the above example (2 + 4 = 2 OR 4). 现在,您可能已经注意到,在上述示例中,逻辑或以及Condition1和Condition2的总和得出相同的值(2 + 4 = 2 OR 4)。 "I know, I'll just sum all of the conditions together!" “我知道,我将所有条件加起来!” you'll say. 你会说。 It's way easier to write List.Sum() than a for loop with ORs and an accumulator. 与使用OR和累加器的for循环相比,编写List.Sum()更容易。 Unfortunately, that doesn't work all the time. 不幸的是,这并不总是有效。

  • Consider again the value of "6" or 0b0110 from above which means "Condition1 and Condition2" are true. 从上面再次考虑值“ 6”或0b0110,这意味着“条件1和条件2”为真。

  • Then combine that with a value that means "Condition0 and Condition1" are set. 然后将其与表示已设置“ Condition0和Condition1”的值组合。 0b0011 or "3" in decimal 0b0011或十进制“ 3”

  • If you do the logical OR - (0b0110 OR 0b0011) you get 0b0111 or decimal 7. This looks like "Condition0, Condition1, and Condition2" are all true. 如果执行逻辑或-(0b0110 OR 0b0011),则将得到0b0111或十进制7。这看起来像“条件0,条件1和条件2”都是正确的。 That seems correct! 看来是对的!

If you added the value together, though, you'll get decimal 9 (6 + 3, or 0b0110 + 0b0011) which comes out to 0b1001. 但是,如果将这些值相加,将得到十进制9(6 + 3或0b0110 + 0b0011),其结果为0b1001。 0b1001 looks like "Condition3 is true and Condition0 is true" That can't be right. 0b1001看起来像“ Condition3为true,Condition0为true”。这是不对的。 How did Condition3 get involved here and what happened to Condition1 and Condition2? Condition3是如何参与这里的,而Condition1和Condition2发生了什么? They were both set when we started! 他们都是在我们开始时就设置好了!

Now, back to the C# world - The "Flags" attribute means "This enum can be made up of one or more orthogonal conditions that can exist or not exist independently". 现在,回到C#世界-“标记”属性的意思是“该枚举可以由一个或多个可以独立存在或不存在的正交条件组成”。 It's up to you, the programmer, to assign values to the different elements of the enum such that they don't overlap (just like in C). 程序员应该自行决定将值分配给枚举的不同元素,以使它们不会重叠(就像在C语言中一样)。 Once that's done, you can happily combine one or more of those orthogonal conditions by performing a logical OR operation on them. 完成后,您可以通过对它们进行逻辑或运算来愉快地组合一个或多个这些正交条件。 You can even define elements in the enum that are combinations of previous defined elements. 您甚至可以在枚举中定义由先前定义的元素组合而成的元素。 Consider the elements 考虑要素

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

In Conclusion: Summing the flags only works in certain scenarios (mainly when each value that is being summed represents a single condition). 结论:对标志求和仅在某些情况下有效(主要是在每个求和的值代表一个条件时)。 In order to write robust code that works correctly in all cases you should probably stick with the logical OR of the flags. 为了编写在所有情况下都能正常运行的健壮代码,您可能应该坚持使用标志的逻辑或。 It might take a few extra lines to write, but it more accurately captures your intent, is easier to maintain, and is more robust if someone passes something you weren't expecting into your method. 写一些代码可能会花费一些额外的时间,但是如果有人将您不期望的内容传递给您的方法,它可以更准确地捕获您的意图,更易于维护,并且更加健壮。 Therefore, to combine all of the elements in your list, you should OR all of them together. 因此,要合并列表中的所有元素,应将所有元素或在一起。 Something like 就像是

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;

Now, you've thrown an extra wrinkle in the works by not making "None" 0, but I'll leave fixing that as an exercise to the reader with the added note that the MSDN guidelines recommend against doing that. 现在,您没有将“ None”设置为0,从而使工作更加混乱,但是我将通过给读者补充一点说明MSDN指南建议不要这样做,来解决这一问题,以供读者练习。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM