Update and Extend an enum C# - c#

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
}

Related

How to loop through check boxes and assign enumeration values when boxes are checked?

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

List of enums to bit string

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.

Identify values in BitValue column

Note: I'm not sure how best to title and tag this question so helpful edits welcome!
I am reverse engineering an ASP.NET Webforms website (for which I don't have the correct version of the source code) to ASP.NET MVC using database first entity framework, and am having difficulty understanding how a particular view/set of data works.
A record has an "Options" field which contains a series of numbers which, when read, identify which of 48 options are true. I'm trying to figure out how to read/write this result.
So, the options table is structured like so:
As you can see there is a BitValue column (Which continues up to 281474976710656); I believe this is what I need to use to identify the options when presented with a number like so: 5120 or 17592186044480
If that number only identified a single option I'd probably be able to figure this out easier but unfortunately there can be several options identified.
So for example, a record has this in it's options field: 17592186044480
The options this identifies (when I refer to the existing website) are:
Procedure (BitValue: 64)
Shore Crew Error (BitValue: 17592186044416)
But I can't for the life of me figure out how both of those numbers translate to the one in the options field!
Any hints?
Ok, so 64 + 17592186044416 = 17592186044480 That helps understand how the number is generated, but how to I reverse this to identify the options that make up the number?
CONCLUSION
I have accepted an answer as, in combination with some comments, it helped me find the solution.
In the end, I wrote out the "options" as an enum like so...
[Flags] public enum options : long
{
Master_Pilot_Exchange = 2,
Bridge_Team_Issues = 4,
Language_Difficulty = 8,
Briefing = 16,
Crew_Competency = 32,
Procedure = 64,
Personal_Performance = 128,
Fatigue = 256,
....
}
and created a function to check each option to see if it is included in the bitValue:
private bool checkBits(long maskIn, int optionId)
{
options mask = (options)maskIn;
var toCheck = db.InitialReportOptions.Single(i => i.InitialReportOptionID == optionId);
options chk = (options)toCheck.BitValue;
bool test = false;
if ((mask & chk) == chk)
{
test = true;
}
//
return test;
}
And when I need to add a new bitValue to a record, I use the following:
options newMask = (options)0;
long bitResult = 0;
foreach(var option in model.ReportOptions)
{
if (option.IsTrue)
{
var bitv = (options)option.BitValue;
bitResult = bitResult | ( (long)newMask | (long)bitv);
}
}
model.InitialReportRecord.Options = bitResult;
I daresay it could be more efficient but it works so I'm happy!
Firstly you need to know the bit values for each of the 48 flags.... Then in C# ...
const int Procedure = 64
if ((myData.InitialReportOption & Procedure) == Procedure)
// Then Procedure flag is active
else // (myData.InitialReportOption & Procedure) == 0
// Procedure is not active
Likewise to enable you would do...
myData.InitialReportOption |= Procedure;
and to disable
myData.InitialReportOption &= ~Procedure;
For more info try this blog...
http://blog.typps.com/2007/10/bitwise-operators-in-c-or-xor-and-not.html

How to set different permissions on parts in N2 CMS admin?

I have setup different users in N2 admin and different users should only be able to do certain things. For example, we should have just one sort of read-only user which can only read things but not edit anything.
How to set up such in N2 admin area?
namespace N2.Security
{
[Flags]
public enum Permission
{
None = 0,
Read = 1,
Write = 2,
Publish = 4,
Administer = 8,
ReadWrite = Write | Read,
ReadWritePublish = ReadWrite | Publish,
Full = ReadWritePublish | Administer,
}
}

how to add multiple enum values with pipe based on conditions?

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

Categories

Resources