Enums to define permission sets in c#
Asked Answered
S

2

8

Instead of splitting each permission into individual columns or sql server table we are rethinking of using Flag attribute to Enum for use with bit wise operations. Our application defines end points ( not the one from rest services) for accessing resources( read, modify, update) and each user is entitled with permissions for example Bob has permissions to Read, Modify resource X so when bob comes and accesses this resource we check if bob has permission x.Now that where we are going to apply this is clear here are my doubts

  • Suppose Bob has Read, Write, Delete permission on resource using Flagged enumerations i would do Permission.Read | Permission.Write | Permission.Delete Is the end result of bit wise AND a integer or another Enum ?

  • For Storing this permission in database table should the column be a integer?

  • If answer to question 1 is Enum then should i define another property on the Permissions enum that represents the integer value of Bit wise and operation?

disclaimer: the Bob referred to in the example does not represent any user in the Stack overflow network of sites or any person. It is just another character

Silicify answered 23/4, 2012 at 4:47 Comment(0)
C
10

To answer your questions in order:

  • Assuming you have set the [Flags] attribute on the enum, and use the correct operator (& and | for bitwise operations) it is essentially both. If you cast the result to an integer, you will get the bitwise and of the relevant values, ie. 7 for your example. If you use .ToString(), then you will get a string back indicating that the value has all three values. I believe that there is a HasFlags() method somewhere, but most code I have seen uses the tried and true bitwise code for comparisons, ie:

    var x = Permissions.Read | Permissions.Write;
    if ((x & Permissions.Read) == Permissions.Read) { print "Success!"; }
    

    From a technical standpoint, C#'s type safety helps keep things sane and the result of |ing or &ing two enums of the same type is another enum of the same type but all enums are simply integers, and can be treated as such in most cases, though some things need explicit casts to/from int.

  • It should be an integral type, yes. I believe the default type for an enum is Int32, however you can set that explicitly if you want to match up the database and code exactly.

  • Given all the above, it can still make a lot of sense to have predefined values for commonly used sets of permissions, for example ReadWrite. In particular, a None element is recommended for all enums by Microsoft, especially if you are going to be casting values. This allows for a fallback and a valid value for freshly initialized variables as well as a sane value for default(Permissions). You can set values in your enum based on other ones like so:

    [Flags]
    enum Permissions {
      None =    0,
      Read =    0x001,
      Write =   0x010,
      Execute = 0x100,
      ReadWrite = Read | Write,
      // [snip]
    }
    
Chesnut answered 23/4, 2012 at 4:58 Comment(5)
@Mathhew just off my head Storing the result of bitwise OR in table as integer. How should i make my permission check in application. speaking in code in here if (IntegerFromDb == Permissions.Read) { print "Success!"; } should i parse the Integer to Enum of type Permissions and do the check?Silicify
@Deeptechtons: You can cast any integer back to the enum type easily: var perms = (Permissions)IntegerFromDb. This is the safest way, however I think you may be able to compare directly with the code I've included above without a cast. Always compare the & with the expected value, especially if using combined values like the suggested ReadWrite because it is possible to have one and not the other and fool a != None style check.Chesnut
@Deeptechtons: Make sure to read my notes in point #3 about sane values for enums though. C# can play up something awful if you cast an integer to an enum that doesn't make sense for the value given.Chesnut
does this mean i do this Permission.Read | Permission.Write and the result integer does not have equivalent integer value in the Permissions enum then it defaults to None ( as in #3)Silicify
@Deeptechtons: No, that means it equates to Permission.Read | Permission.Write, as expected. But you tried to cast say 9 to the enum I provided, it wouldn't work nicely. I'm not 100%, but I think it may even throw an exception.Chesnut
K
5
  1. Bitwise OR/AND for values of enum marked with [Flags] are values of the same enum.
  2. Integer is reasonable filed to store enum values in database.
  3. No, you don't need to add additional enum values, but may do so for conviniece.

Normaly you define such enums with FlagsAttribute i.e.

[Flags] enum My {
  None = 0, Read =1, Write =2, Delete = 4
};

When defined this way you can combine different values with | (or) operation:

My readAndWrite = My.Read | My.Write;

Bitwise AND will give you 0 for enum values that represent unique flags, but commonly used to mask other bits:

bool doIHaveWrite = (readAndWrite & My.Write) == My.Write;

Note that logical AND (&&) can't be applied to enum values.

Kob answered 23/4, 2012 at 4:57 Comment(1)
+1 neat you guys both have helped me If there was anyway i can mark both as answers , Gosh no feature as such on SO now. I will upvote youSilicify

© 2022 - 2024 — McMap. All rights reserved.