From the client I get a List where each int value is the enum int value of the Enum DayOfWeek.
The list contains only those int values (days) which are visible in a time planner.
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?
Just know that the Saturday has an index of 6 while my DayOfWeek enum has 32 as value.
[Flags]
public enum DayOfWeek
{
Sunday = 0,
Monday = 1,
Tuesday = 2,
Wednesday = 4,
Thursday = 8,
Friday = 16,
Saturday = 32,
NotSet = 64,
}
UPDATE
This is the working solution code from MarcinJuraszek which is just changed to my needs:
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.
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.
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.
You can use LINQ also to aggregate flags into single int
value:
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; this fits the semantics better.
(2) For every DayValue, set
dayOfWeek |= (DayOfWeek) Math.Pow(2,DayValue);
DayValue is the input vale coming in: 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. If you want just all days, you could do (DayOfWeek)127
or just add AllDays = 127
to the enum.
Understanding the answer to this question requires a deeper understanding of the [Flags] attribute on your enum class. You can read about this attribute (or read some guidelines about how to use it) here at 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.
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. What you would do then is define the conditions such that:
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
Therefore, we can combine those two lists and see that:
If we need to represents that Condition1 and Condition2 have occurred, then that would mean bits 1 and bits 2 are set. In binary, that's 0b0110 and in decimal that's "6". A value that represents Condition1 and Condition2 is simply the logical OR of Condition1 and Condition2. 0b0010 OR 0b0110 is 0b0110. 2 OR 4 is 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). "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. 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.
Then combine that with a value that means "Condition0 and Condition1" are set. 0b0011 or "3" in decimal
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. 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. 0b1001 looks like "Condition3 is true and Condition0 is true" That can't be right. How did Condition3 get involved here and what happened to Condition1 and 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". 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). 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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.