Author Topic: Bitwise setting storage  (Read 9524 times)

0 Members and 1 Guest are viewing this topic.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Bitwise setting storage
« Reply #15 on: May 19, 2013, 09:13:45 AM »
I read some other documentation that actually encouraged overlapping bits as a way of making the code more understandable, but not with the abbreviated form I used in the original bit of code.

As far as I am concerned, creating an enum value for flag combinations is not only inefficient from the coding point of view, but negates the reason to use flags in the first place.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

TheMaster

  • Guest
Re: Bitwise setting storage
« Reply #16 on: May 20, 2013, 02:59:22 AM »
Code - C#: [Select]
  1. [Flags]
  2. public enum MyEnum
  3. {
  4.      read = 1,
  5.      write = 2,
  6.      create = 4,
  7.      delete = 8,
  8.      rwcd = read | write | create | delete
  9. }
  10.  

This kind of defeats the purpose of what an enum with the FlagsAttribute represents, doesn't it?

Its ToString() method wouldn't return the string "read, write, create, delete" but "rwcd" instead, when encountering the combined value. If I'm interpreting the doc correctly, this is all that the FlagsAttribute does.


Did you read the doc you refer to above?

Specifically, under "Guidelines for FlagsAttribute and Enum", the third bulleted item:

Quote
Consider creating an enumerated constant for commonly used flag combinations. For example, if you have an enumeration used for file I/O operations that contains the enumerated constants Read = 1 and Write = 2, consider creating the enumerated constant ReadWrite = Read OR Write, which combines the Read and Write flags. In addition, the bitwise OR operation used to combine the flags might be considered an advanced concept in some circumstances that should not be required for simple tasks.

Beyond that, an enumerated constant can be the logical union of several other constants, but can still have a different meaning beyond that, as is the case in the MatchPropFlags enum I posted above.

Here it is again, with the revision that I had to make when entity Transparency was introduced:

This was the enum before the Entity.Transparency property was introduced:

Code - C#: [Select]
  1.  
  2.    [Flags]
  3.    public enum MatchPropFlags
  4.    {
  5.       Color = 0x1,
  6.       Layer = 0x2,
  7.       Linetype = 0x4,
  8.       Thickness = 0x8,
  9.       LinetypeScale = 0x10,
  10.       Text = 0x20,
  11.       Dimension = 0x40,
  12.       Hatching = 0x80,
  13.       Lineweight = 0x100,
  14.       PlotStyleName = 0x200,
  15.       Polyline = 0x400,
  16.       Viewport = 0x800,
  17.       Table = 0x1000,
  18.       Material = 0x2000,
  19.       ShadowDisplay = 0x4000,
  20.       Multileader = 0x8000,
  21.       All = 0xFFFF,
  22.       Entity = Color | Layer | Linetype | Thickness
  23.          | LinetypeScale | Material | Lineweight
  24.          | PlotStyleName | ShadowDisplay
  25.    };
  26.  
  27.  

When the Entity.Transparency property was introduced, the Transparency bit flag was added, and the Entity constant was modified to include it:

Code - C#: [Select]
  1.    
  2.   Transparency = 0x10000,  
  3.  
  4.   Entity = Color | Layer | Linetype | Thickness
  5.      | LinetypeScale | Material | Lineweight
  6.      | PlotStyleName | ShadowDisplay | Transparency
  7.  
  8.  

The point to the Entity constant (which like the rwcd constant in the example you quoted), is to specify that all Entity properties are to be matched, in a non-literal way. IOW, it means all entitiy properties, including any that are added in the future, which is not exactly the same as 'all entity properties that existed when the enum was defined or used'.

So, when the Transparency flag was added to support entity transparency in MATCHPROPS, all existing code that used the Entity member, rather than explicitly specifying each of the flags it represents, automatically supported matching entity Transparency without having to be revised.

If in my code where this enum was used, I instead used the individual flags when the intent was to match all entity properties, then I would have had to revise each place where those flags were used, and add the Transparency flag.

So, in this case the Entity member has its own meaning, in spite of the fact that its value is the logical or of all the flags for each Entity's property. Perhaps its meaning would be clearer if I had given it the name "AllSupportedEntityProperties" ?

In the case of the example you quoted, it could have the meaning "full permissions", which could make its meaning slightly different then read+write+create+delete, as well.

The FlagsAttribute itself doesn't really do anything, but it is recognized in a number of places in the framework. For example, the PropertyGrid will behave differently when that attribute is applied to a property of an Enum type. There are also cases where data binding might specifically look for the flag to bind to a specific field, rather than the aggregated value.

 
[I revised this post after having read the referenced docs]
« Last Edit: May 20, 2013, 06:42:59 AM by TT »

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Bitwise setting storage
« Reply #17 on: May 20, 2013, 12:39:22 PM »
In case any of you guys did not know if you have enumeration you deal with a lot you can use extension methods to make the enumeration act as though it has methods.
 
Simple example and sure you guys could come up with some useful ones for your needs.
Code - C#: [Select]
  1.  
  2.    [Flags]
  3.     public enum Settings
  4.     {
  5.         CanCopy = 1,
  6.         CanOpen = 2,
  7.         CanEdit = 4,
  8.         CanDelete = 8
  9.     }
  10.     public static class SettingsExtension
  11.     {
  12.         public static Settings SetFlag(this Settings set, Settings newFlag)
  13.         {
  14.             return set | newFlag;
  15.         }
  16.         public static Settings ClearFlag(this Settings set, Settings clearFlag)
  17.         {
  18.             return set & ~clearFlag;
  19.         }
  20.     }

 

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Bitwise setting storage
« Reply #18 on: May 20, 2013, 02:43:27 PM »
whoa .. that is cool ... I'll have to remember that!
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

kaefer

  • Guest
Re: Bitwise setting storage
« Reply #19 on: May 20, 2013, 02:46:07 PM »
Did you read the doc you refer to above?

I wish I had read the part about the FlagsAttribute being a mere convention to mark enumerations that can be treated as bit fields. Apart from the inconsistency of treating certain bit combinations specially, I should be agnostic to what the third bulleted item suggests. The surprise was in the paucity of actual functionality of the FlagsAtrribute.

<example of genial enum encapsulated version dependency omitted, which does not rely on the presence of the FlagsAttribute>

Quote
The FlagsAttribute itself doesn't really do anything, but it is recognized in a number of places in the framework. For example, the PropertyGrid will behave differently when that attribute is applied to a property of an Enum type. There are also cases where data binding might specifically look for the flag to bind to a specific field, rather than the aggregated value.

This latter sounds rather interesting, and perhaps pertinent, considering the need to bind bitwise-coded settings to an UI.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Bitwise setting storage
« Reply #20 on: May 20, 2013, 02:58:34 PM »
At least in my application, I won't be binding settings to controls because the settings will be read only or not accessible for the current user. For the super-admin, who has access to edit user settings, changing the settings will be done one by one.

... although, binding could present a simpler option to managing user settings ... is it possible to bind multiple controls to a single enum variable?
For example, in our documents permission group, there are 8 permissions. The DocPerm database value can be any value from 0 to 255 representing any combination of settings. All permission controls are checkboxes .. so CheckBox1.checked = HasThisPermission(); or is there a binding that can be set? Then I can simply update the database with the bound data.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Bitwise setting storage
« Reply #21 on: May 21, 2013, 10:28:46 PM »
A good discussion on Stack Overflow clarifying the Enum Flags Attribute -  http://stackoverflow.com/questions/8447/enum-flags-attribute.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Bitwise setting storage
« Reply #22 on: May 21, 2013, 10:56:38 PM »
I read that thread before embarking on this journey. It is a good explanation.

There is one thing that I did discover. The HasFlag method wasn't introduced until .Net4.0

Initially this project was supposed to be .Net3.5. Due to the shared nature of the deployment server the hosting company wouldn't install the latest versions of .Net just in case it might affect someone elses website. Apparently they don't understand the nature of the .net libraries and the fact that the versions are targeted. Anyway, we have since went from shared hosting to owning a webserver outright. I am free to develop with the latest libraries ... makes life easier ;-)
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Bitwise setting storage
« Reply #23 on: May 22, 2013, 12:15:38 AM »
Hi Keith,
 
You mentioned this needing to be efficient and not sure how often and how many calls you will make so might not be worth it, but if you look at HasFlag signature it takes a Enum as its parameter.
Code - C#: [Select]
  1.         [SecuritySafeCritical, __DynamicallyInvokable]
  2.         public bool HasFlag(Enum flag)
  3.         {
  4.             if (flag == 0)
  5.             {
  6.                 throw new ArgumentNullException("flag");
  7.             }
  8.             if (!base.GetType().IsEquivalentTo(flag.GetType()))
  9.             {
  10.                 throw new ArgumentException(Environment.GetResourceString("Argument_EnumTypeDoesNotMatch", new object[] { flag.GetType(), base.GetType() }));
  11.             }
  12.             return this.InternalHasFlag(flag);
  13.         }
  14.  
  15.  

 
So any value you pass in will get boxed.
 
Might help to use a extension method to save some cycles.
Maybe something similar as last method below IsSet.
Code - C#: [Select]
  1.  
  2.     [Flags]
  3.     public enum Settings
  4.     {
  5.         CanCopy = 1,
  6.         CanOpen = 2,
  7.         CanEdit = 4,
  8.         CanDelete = 8
  9.     }
  10.     class Program
  11.     {
  12.         static void Main(string[] args)
  13.         {
  14.             Settings settings = Settings.CanCopy;
  15.             settings = settings.SetFlag(Settings.CanDelete);
  16.             Console.WriteLine(settings.IsSet(Settings.CanCopy));
  17.             Console.WriteLine(settings.IsSet(Settings.CanDelete));
  18.             Console.WriteLine(settings.IsSet(Settings.CanEdit));
  19.             Console.Read();
  20.         }
  21.     }
  22.     public static class SettingsExtension
  23.     {
  24.         public static Settings SetFlag(this Settings set, Settings newFlag)
  25.         {
  26.             return set | newFlag;
  27.         }
  28.         public static Settings ClearFlag(this Settings set, Settings clearFlag)
  29.         {
  30.             return set & ~clearFlag;
  31.         }
  32.         public static bool IsSet(this Settings set, Settings testFlag)
  33.         {
  34.             if (testFlag == 0)
  35.             {
  36.                 throw new ArgumentNullException("testFlag");
  37.             }
  38.             return (set & testFlag) == testFlag;
  39.         }
  40.     }
  41.  
  42.  

 

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Bitwise setting storage
« Reply #24 on: May 22, 2013, 06:57:43 AM »
This is a web application, so I am not sure that any method is going to be super efficient, but as it stands right now I've used the HasFlag method to verify the permissions.

When a user logs into the website, their credentials are verified against those stored in the database. If they are successful during login, a user object is created. Of course, this being the web, the user object isn't persistent, so ... whenever the user browses to a different page, their credentials are verified against those in the database and the page is rendered according to their permissions.

The user object is not recreated on postback unless it is needed.

The inefficiencies are introduced because before any page can be rendered, every possible permission has to be evaluated so the proper controls can be created. When you have over 200 permissions, it gets a bit hairy, although, by grouping the permissions, I can short circuit alot of the checks, because for example, if the user doesn't have the "CanSeeAdminTab" property set, we don't need to check the 50 or so admin permissions because the admin tab will never be rendered anyway. The same thing happens with the other 16 permission groups.

I am sure there could be some tweaks that would make the process more efficient, but right now, the goal is to get a working system to verify user credentials.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

TheMaster

  • Guest
Re: Bitwise setting storage
« Reply #25 on: May 22, 2013, 04:46:02 PM »
Hi Keith,
 
You mentioned this needing to be efficient and not sure how often and how many calls you will make so might not be worth it, but if you look at HasFlag signature it takes a Enum as its parameter.
Code - C#: [Select]
  1.         [SecuritySafeCritical, __DynamicallyInvokable]
  2.         public bool HasFlag(Enum flag)
  3.         {
  4.             if (flag == 0)
  5.             {
  6.                 throw new ArgumentNullException("flag");
  7.             }
  8.             if (!base.GetType().IsEquivalentTo(flag.GetType()))
  9.             {
  10.                 throw new ArgumentException(Environment.GetResourceString("Argument_EnumTypeDoesNotMatch", new object[] { flag.GetType(), base.GetType() }));
  11.             }
  12.             return this.InternalHasFlag(flag);
  13.         }
  14.  
  15.  

 
So any value you pass in will get boxed.
 

The initial implementation of HasFlag() had major performance issues that were reported on connect and written about elsewhere, that were addressed in .NET 4.0

Code - C#: [Select]
  1. public bool HasFlag(Enum flag)
  2. {
  3.    if (!base.GetType().IsEquivalentTo(flag.GetType()))
  4.    {
  5.       throw new ArgumentException(Environment.GetResourceString("Argument_EnumTypeDoesNotMatch", new object[] { flag.GetType(), base.GetType() }));
  6.    }
  7.    ulong num = ToUInt64(flag.GetValue());
  8.    return ((ToUInt64(this.GetValue()) & num) == num);
  9. }
  10.  
  11.  

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Bitwise setting storage
« Reply #26 on: May 22, 2013, 05:25:49 PM »
So, what is the prognosis? Is using HasFlag the best alternative? I do have to process 200+ permissions on each page render that is not a postback.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

TheMaster

  • Guest
Re: Bitwise setting storage
« Reply #27 on: May 22, 2013, 05:39:52 PM »
So, what is the prognosis? Is using HasFlag the best alternative? I do have to process 200+ permissions on each page render that is not a postback.

Jeff's point about boxing is still an issue (an argument of type Enum will be boxed), and HasFlag() is much slower than using the 'flag & bits == bits' test, but this does not become a major issue unless you are calling it at a very high frequency. 

Most programmers will opt for HasFlags() simply because it is less typing, which is fine as long as its not being called at a very high frequency.


Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Bitwise setting storage
« Reply #28 on: May 22, 2013, 05:52:57 PM »
Well, as I stated earlier, because this is a webpage, I can't persist the user object and I have to validate on each new page view. The good thing is that I don't have to validate on postback and there are only a dozen or so pages that are viewed. For the most part, the user will remain on the same page for the entire session until they log out.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Bitwise setting storage
« Reply #29 on: May 22, 2013, 06:37:33 PM »
For the most part, the user will remain on the same page for the entire session until they log out.

Have you looked into SignalR and/or Single Page Applications?

Also, the ASP.NET [Authorize] Attribute may be helpful? See also http://stackoverflow.com/q/970271/492 and related questions.