I was trying to add multiple enum values to a variable based on conditions. For example, I have something like this:
SharedAccessBlobPermissions t = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read;
if user has chosen other available enum values on the UI, i want to add them was well. But it looks like we can only write it on one line and can't add multiple values later on.
Any idea how can I achieve this?
[Update]
Based on the answers, this is what I wrote
var t= new SharedAccessBlobPermissions();
if (isAllowRead)
{
t = SharedAccessBlobPermissions.Read;
}
if (isAllowWrite)
{
t |= SharedAccessBlobPermissions.Write;
}
If SharedAccessBlobPermissions has been declared with [Flags] attribute
you can do some set arithemtics. If initially
SharedAccessBlobPermissions t = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read;
Addtion:
// Add SharedAccessBlobPermissions.Delete and SharedAccessBlobPermissions.Clear
t |= SharedAccessBlobPermissions.Delete | SharedAccessBlobPermissions.Clear;
Subtraction:
// Remove SharedAccessBlobPermissions.Delete
t = (t | SharedAccessBlobPermissions.Delete) ^ SharedAccessBlobPermissions.Delete;
You can keep adding more values to the bitmask by bitwise-oring them with the current value:
t |= SharedAccessBlobPermissions.AnotherOption
You need to use Flags attribute.
See the following example:
[Flags]
enum DaysOfWeek
{
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64
}
public void RunOnDays(DaysOfWeek days)
{
bool isTuesdaySet = (days & DaysOfWeek.Tuesday) == DaysOfWeek.Tuesday;
if (isTuesdaySet)
//...
// Do your work here..
}
public void CallMethodWithTuesdayAndThursday()
{
this.RunOnDays(DaysOfWeek.Tuesday | DaysOfWeek.Thursday);
}
I suggest you to read the following Thread
Here is another useful answer
Related
I have a group of check boxes, to be precise there are 3 boxes. It works for me when using if statement but I wonder there is a way to loop through check boxes and assign enumeration values when a box is checked or more.
The code looks like this:
if (chkTomato.Checked && !chkLettuce.Checked && !chkCarrot.Checked)
{
cart.VegChosen = Veggies.Tomato;
}
else if (!chkTomato.Checked && chkLecctuce.Checked && !chkCarrot.Checked)
{
cart.VegChosen = Veggies.Lecctuce;
}
else if (!chkTomato.Checked && !chkLecctuce.Checked && chkCarrot.Checked)
{
cart.VegChosen = Veggies.Carrot;
}
else if (chkTomato.Checked && chkLettuce.Checked && chkCarrot.Checked)
{
cart.VegChosen = Veggies.All;
}
else if (chkTomato.Checked && chkLettuce.Checked && !chkCarrot.Checked)
{
cart.VegChosen = Veggies.TomatoAndLettuce;
}
else if (chkTomato.Checked && !chkLettuce.Checked && chkCarrot.Checked)
{
cart.VegChosen = Veggies.TomatoAndCarrot;
}
else if (!chkTomato.Checked && chkLettuce.Checked && chkCarrot.Checked)
{
cart.VegChosen = Veggies.LettuceAndCarrot;
}
else
{
cart.VegChosen = Veggies.None;
}
I want to find out a way to loop it in case there are more than just 3 check boxes, the if statement would be very long.
Thank you!
While this doesn't use loops, I expect this is what you're trying to achieve. Assuming your enum is declared like this:
[Flags]
public enum Veggies
{
None = 0,
Tomato = 1,
Lettuce = 2,
Carrot = 4,
TomatoAndLettuce = Tomato | Lettuce,
TomatoAndCarrot = Tomato | Carrot,
LettuceAndCarrot = Lettuce | Carrot,
All = Tomato | Lettuce | Carrot
}
Then you should be able to use a similar bitwise approach to assign values:
Veggies selectedVeggies = Veggies.None;
if (chkTomato.Checked)
{
selectedVeggies = selectedVeggies | Veggies.Tomato;
}
if (chkLettuce.Checked)
{
selectedVeggies = selectedVeggies | Veggies.Lettuce;
}
if (chkCarrot.Checked)
{
selectedVeggies = selectedVeggies | Veggies.Carrot;
}
cart.VegChosen = selectedVeggies;
The net result of this will be the same as your current set of if statements. The reason we use 1, 2, 4, etc. for the enum values is because there isn't overlap between them when rendered in binary (1 is 001, 2 is 010, 4 is 100, etc.) so that specific bit can only identify that one enum value.
Also note that declarations such as TomatoAndLettuce and TomatoAndCarrot are perhaps also unnecessary, since you can use Enum.HasFlag().
For example:
var selectedVeggies = Veggies.Tomato | Veggies.Carrot;
// or var selectedVeggies = Veggies.TomatoAndCarrot; // effectively the same as above
if (selectedVeggies.HasFlag(Veggies.Tomato))
{
cart.Add(new Tomato());
}
if (selectedVeggies.HasFlag(Veggies.Carrot))
{
cart.Add(new Carrot());
}
// cart ends up with a Tomato and a Carrot
Further reading: What does the bitwise or | operator do?
Create the enum like so:
enum Veggies {
Tomato = 1 << 0,
Lettuce = 1 << 1,
Carrot = 1 << 2,
All = Tomato | Lettuce | Carrot
}
This makes the value of Veggies.Tomato = 1 which is 0000 0001 in bits, Veggies.Lettuce = 2 which is 0000 0010, and Veggies.Carrot = 4 which is 0000 0100.
It is important to have the enum values as bit-shifted 1's (powers of 2) so that you can combine two enum values later as an int like I've done with Veggies.All, which is 0000 0111.
Change VegChosen to an int, then simply change your code to something like this to bitwise-or the enum value into the VegChosen int:
cart.VegChosen = 0;
if(chkTomato.Checked) cart.VegChosen |= Veggies.Tomato;
if(chkLettuce.Checked) cart.VegChosen |= Veggies.Lettuce;
if(chkCarrot.Checked) cart.VegChosen |= Veggies.Carrot;
Later if you want to test what veggies were chosen from cart.VegChosen you can bitwise-and with one of the enum values and check if it's 0 like so:
if((cart.VegChosen & Veggies.Carrot) != 0)
{
//... cart.VegChosen contains Veggies.Carrot
}
if((cart.VegChosen & Veggies.Lettuce) != 0)
{
//... cart.VegChosen contains Veggies.Carrot
}
//etc
This is typically ~50% faster/more performant than Enum.HasFlag() because HasFlag() contains various sanity checks, but if you're not programming specifically for performance it's better to use what is easier to use and read and in that respect I would recommend Llama's answer.
Once you e implemented Llamas answer of making a flags enum you can put all your checkboxes in a groupbox and do this:
var veg = Veggies.None:
groupbox.Controls
.OfType<CheckBox>()
.Where(c => c.Checked)
.ToList()
.ForEach(c => veg |= Enum.Parse<Veggies>(c.Name[3..]));
Then all you have to do is add more enum members and add more checkboxes where the checkbox name is like "chkXXX" where xxx is the name of the enum member
This is a looping construct: it gets all the controls on the groupbox and filters to only those of type checkbox, then reduces it to only checked checkboxes. It turns this into a list (so we can foreach it, because foreach is a list thing not a LINQ thing). Foreach will visit every checkbox and ask if it is checked, it will OR the existing flags enum value with the result of parsing the checkbox name (dropping the first 3 chars) to a Veggies. At the end of it your veg variable will represent all the checkboxes that were Checked
Note that using ranges and even Enum.Parse<T> required a fairly modern version of c# - if you're running a version that doesn't support ranges you can use Substring(3). You should make sure that all your checkbox names are well aligned with your enum names. If you want to get really trick you could create your checkboxes dynamically by enumerating the Enum and putting the enum value as the checkbox Tag when you add the control to the form (dynamically, in incrementing positions) this way your form will just adapt automatically to however many enum members you have
I am attempting the below Question, but can not seem to figure out how to extend the enum:
Question:
Each account on a website has a set of access flags that represent a users access.
Update and extend the enum so that it contains three new access flags:
A Writer access flag that is made up of the Submit and Modify flags.
An Editor access flag that is made up of the Delete, Publish and Comment flags.
An Owner access that is made up of the Writer and Editor flags.
For example, the code below should print "False" as the Writer flag does not contain the Delete flag.
Console.WriteLine(Access.Writer.HasFlag(Access.Delete))
using System;
public class Account
{
[Flags]
public enum Access
{
Delete,
Publish,
Submit,
Comment,
Modify
}
public static void Main(string[] args)
{
//Console.WriteLine(Access.Writer.HasFlag(Access.Delete)); //Should print: "False"
}
}
You can do this by giving each flag of your enum a value that, if represented in the binary system, consists of only zeroes and a 1.
[Flags]
public enum Access
{
// Simple flags
Delete = 1, // 00001
Publish = 2, // 00010
Submit = 4, // 00100
Comment = 8, // 01000
Modify = 16, // 10000
// Combined flags
Editor = 11, // 01011
Writer = 20, // 10100
Owner = 31 // 11111
}
This way, writer will have both the submit and modify flag, but not the delete flag.
Why does this work?
The HasFlag method basically does a bitwise AND operation. So when you check whether delete is in the editor flag, it does this. Only if both bits are 1, the resulting bit will also be 1, otherwise 0.
00001
01011
----- &
00001
Check whether delete is in writer:
00001
10100
----- &
00000
If the result is the same as the flag you're passing as a parameter, that means the flag is included!
More literal
You can define the numbers as binary literals as well. That way it is easier to see at a glance what's what.
[Flags]
public enum Access
{
// Simple flags
Delete = 0b00001,
Publish = 0b00010,
Submit = 0b00100,
Comment = 0b01000,
Modify = 0b10000,
// Combined flags
Editor = Delete | Publish | Comment,
Writer = Submit | Modify,
Owner = Editor | Writer
}
or, as I like to write it
[Flags]
public enum Access
{
// Simple flags
Delete = 1,
Publish = 1 << 1,
Submit = 1 << 2,
Comment = 1 << 3,
Modify = 1 << 4,
// Combined flags
Editor = Delete | Publish | Comment,
Writer = Submit | Modify,
Owner = Editor | Writer
}
I have created a permission enum Flags that controls access:
[Flags]
public enum PermissionEnum
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
All = 7
}
If someone requests access the different enum values will be added to a list:
List<PermissionEnum> permissions = new List<PermissionEnum> { 1, 4 }
How can I flatten out the list of enums to a bit string?
E.g.
[1,4] = "101"
You're doing it the wrong way. Instead of a list, you should store in a single PermissionEnum variable and for each permission to be added, do a bitwise or:
PermissionEnum pe = PermissionEnum.None; //Current value:0
pe |= PermissionEnum.Read; //Add Read permission. Current value: 1
pe |= PermissionEnum.Delete;//Add Delete permission. Current value: 5
Then you can display the value converting the int to a string:
string result = Convert.ToString((int)pe, 2); //yields "101"
To remove a permission, use bitwise and and bitwise not
pe &= ~PermissionEnum.Read; //Removes Read permission. Current value: 4
Also, to check if some permission is setted, use bitwise and and check if is greater than 0:
bool canRead = (pe & PermissionEnum.Read) > 0;
Step 1
Combine your list of flags into a single enum value:
PermissionEnum combined = permissions.Aggregate(PermissionEnum.None,
(cmb, perm) => cmb | perm);
Step 2
Convert the combined value into a bit string:
string bitString = Convert.ToString((int)combined, 2);
Note that if you can change the interface so you just get the combined enum instead of a list, you can avoid step 1 altogether.
if i declare an enum like
enum Weekdays
{
Mon = 1,
Tue = 1,
Wen = 1,
Thi,
Fri,
Sat,
Sun
}
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);//Prints Tue why?
now if i change Weekdays and do the same operation as follows
enum Weekdays
{
Mon = 1,
Tue = 1,
Wen = 1,
Thi = 1,
Fri,
Sat,
Sun
}
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);//Prints Thi !!!!!How?
What is really happening here?
When you write out your value like this, it ends up getting ToString() called on it.
Console.WriteLine(obj);
If you dig into the code far enough down, it's calling Enum.GetName() on your value.
Regarding multiple enum values with the same underlying value, the Enum.GetName page on MSDN says:
If multiple enumeration members have the same underlying value, the GetName method guarantees that it will return the name of one of those enumeration members. However, it does not guarantee that it will always return the name of the same enumeration member. As a result, when multiple enumeration members have the same value, your application code should never depend on the method returning a particular member's name.
It doesn't state how it determines which name to return if the values on two or more are the same.
The docs for Enum.ToString() include the same warning, in slightly different wording.
Digging a little deeper, the method above makes a call to Array.BinarySearch, passing it an array of numbers representing all values in your enum, and a number representing the value you want to print.
So you have an array with multiple 1's in it, and you're searching for a 1. The docs for that call are similar:
Duplicate elements are allowed. If the Array contains more than one element equal to value, the method returns the index of only one of the occurrences, and not necessarily the first one.
Again, it doesn't state how a selection is made, just that it'll be unreliable.
When you assign similar values, the result will be unexpected but I think it will evaluate for two cases:
When n is even:
(n/2)
When n is odd:
(n/2)+1
If I change the enum like this:
enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1,Fri=1,Sat=1, Sun=1, Mon2=1, Mon3=1}
// n is odd = 9
// (n/2)+1 = 5
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);
The result will be Fri, Now lets change the enum again:
enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1,Fri=1,Sat=1, Sun=1,Mon2=1}
// n is even = 8
// (n/2) = 4
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);
The result is now Thi, Again change the enum:
enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1,Fri=1,Sat=1, Sun=1}
// n is odd = 7
// (n/2)+1 = 4
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);
The result is now Thi, Again change the enum:
enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1,Fri=1,Sat=1}
// n is even = 6
// (n/2) = 3
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);
The result is now Wen, Again change the enum:
enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1,Fri=1}
// n is odd = 5
// (n/2)+1 = 3
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);
The result is now Wen, Changing the enum again:
enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1}
// n is even = 4
// (n/2) = 2
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);
The result is now Tue, Changing the enum again:
enum Weekdays {Mon=1,Tue=1,Wen=1}
// n is odd = 3
// (n/2)+1 = 2
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);
The result is now Tue.
Even though this is explaining the behavior perfectly but this may not always happen or may not happen since I have not checked this for more cases but as MSDN says you should not assume about such output when the enum have same values for different names...
That said, I think you can easily understand now what is happening in your code.
Ref.: Link
Edit:
#GrantWinney's answer led me to this, He has written that Array.BinarySearch is passed the array of values and the value to search for so I realized from the name Array.BinarySearch that it is definitely using a BinarySearch and that explains everything...
Binary Search will divide the array like this:
Mid = {Low(which is the starting index) + High (which is the last index of array)}/2
and then Check for
if (Mid == value) return index;
else
if the value is smaller or equal move left other wise move right of the array
So this explains it how the enum values are printed if their are multiple names for the value you are trying to print.
Your Original Question
enum Weekdays
{
Mon = 1,
Tue = 1,
Wen = 1,
Thi,
Fri,
Sat,
Sun
}
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);//Prints Tue why?
It prints Tue because a call to Array.BinarySearch will be made passing the array
{1, 1, 1, 2, 3, 4, 5}
and a value to search which is 1...
So the BinarySearch will do this:
Mid = {Low(0) + High(6)} / 2
if (Mid == value) return index
else move left
After moving left again the Mid will be calculated:
High = Mid - 1; // now only the left sub-array will be searched
Mid = {Low(0) + High(2)} / 2
if (Mid == value) return index // here the condition will be true and you will be returned with `Tue`
The 2nd example in your Question:
enum Weekdays
{
Mon = 1,
Tue = 1,
Wen = 1,
Thi = 1,
Fri,
Sat,
Sun
}
Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);//Prints Thi !!!!!How?
As I have written above a call to Array.BinarySearch will be made and array:
{1, 1, 1, 1, 2, 3, 4}
will be passed with value = 1 to search...
Apply the BinarySearch algorithm on the array and it will evaluate to Thi.
As Per MSDN If multiple enumeration members have the same underlying value and you attempt to retrieve the string representation of an enumeration member's name based on its underlying value, your code should not make any assumptions about which name the method will return.
I have an Enum of flags to represent the days of the week, with a few extra values that indicate weekdays, weekends, every day, or no days.
Here's the Enum:
[Flags]
public enum DayOfWeek : short
{
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64,
Weekday = 62,
Weekend = 65,
Everyday = 127,
None = 0
}
I also have a View Model with a property, DayOfWeek with a type of DayOfWeek.
In my View, I need to create a checkbox for each day of the week and somehow appropriately check the boxes based on which days have been saved.
How can I do this?
I found a good solution.
Here's what I came up with:
#foreach (DayOfWeek item in Enum.GetValues(typeof(DayOfWeek)))
{
if (0 < item && (item <= DayOfWeek.Friday || item == DayOfWeek.Saturday))
{
#Html.Label("DayOfWeek", item.ToString())
#Html.CheckBox("DayOfWeek", (Model.DayOfWeek.HasFlag(item)), new { value = item })
}
}
The conditional statement within the loop is to ensure that only the actual days get displayed.
This works for my purposes, and the concept can be easily applied to other Enumerations. Specific implementation will need some changes, but you get the idea.
You can iterate through your Enum like this:
foreach (var val in typeof(DayOfWeek).GetEnumNames())
....
Also you can Pars and convert back a string to your Enum
var day = Enum.Parse(typeof(DayOfWeek) , yourString);
yourstring can be anything you want for example the name of the checkbox.
I don't know more about your problem and your project architecture, it's up to you to adapt these options to your problem.I hope this helps.
It's a fairly manual process... To check if Sunday is selected, for example:
bool isSunday = (dayOfWeekEnum & DayOfWeek.Sunday) == DayOfWeek.Sunday;