Negative flags in C#
Asked Answered
R

4

8

Hey, is there any way to store negative flags in C#? For example I have the following flags enum that represents some styles:

[Flags]
public enum Styles
{
    Default = 0,
    Bold = 1,
    Italic = 2
}

Now I have multiple objects, those styles can be applied to, and later all related are combined (i.e. other object may inherit some previously set styles). In addition to that, I would like to define negative flags, that basically undo inherited styles. So if the style was previously set to Styles.Bold | Styles.Italic and the object inherits that style but has a negative Styles.Bold flag set, then the result should be just Styles.Italic.

Is there any mechanism that already does this? I basically though of two ways now: First is defining NotXY enum values, that are then somehow parsed to eliminate the XY values if set.

The other is simply defining two fields, positive and negative flags, where the negative flags are specially defined in an extra field and I get the resulting flags by simply doing positiveFlags ^ negativeFlags.

edit:

If this wasn't clear, I need to store each of those intermediate objects' styles. So it could be for example like this:

object1: Default
object2: Bold
object3: -Bold Italic

And if object3 also inherits the values of 1 and 2, then the final result should be just Italic.

Another example in response to Kieren Johnstone's question, and per my statement in the comment that negative values only apply on the current level:

1: Bold
2: -Bold -Italic
3: Italic

2 eliminates both Bold and Italic from previous objects, but then shouldn't apply any further (positive values should though), so the final value would be Italic again.

Retrogradation answered 4/4, 2011 at 10:13 Comment(0)
S
9

So should the negative always have precedence? What if you start with a NotBold and then add a Bold?

If it's always positive overridden by negative when present, I'd suggest two fields:

private Styles baseStyles;
private Styles overrideDisableStyles;
public Styles ResultsStyles { return baseStyles & ~overrideDisableStyles; }

Or you could create a helper class with SetStyle and UnsetStyle:

public void SetStyle(Styles styles)
{
    this.styles |= styles;
}

public void UnsetStyle(Styles styles)
{
    this.styles &= ~styles;
}

For reference, positiveFlags ^ negativeFlags will NOT work. Consider the situation where Bold is not set but NotBold is. The result will be Bold even though the only specified flag was NotBold.

Finally, if you're doing anything commerical, in-depth, any more complex than you describe here and want to have extendable/expandable style inheritance, you should design it correctly with an object graph/class hierarchy - start by defining a Style class that has one or more parent objects. Each Style could have a set of property name/value pairs that override anything from the parent - there could be a Properties collection that returns these overrides, and an Evaluate method that starts at the root object and navigates to the style in question, building a resulting list of properties for you to use.

Hope that helps.

Sextillion answered 4/4, 2011 at 10:24 Comment(1)
Thank you, that's a very good point I didn't consider yet. I guess in my case I only want positive values to be inherited, so negative values will only apply on the current "level" (they still need to be stored appropriately).Retrogradation
H
2

I would recommend going with the second approach. It seems more obvious and simpler to me.

Hypomania answered 4/4, 2011 at 10:15 Comment(0)
T
1

The other is simply defining two fields, positive and negative flags, where the negative flags are specially defined in an extra field and I get the resulting flags by simply doing positiveFlags ^ negativeFlags.

This seems most natural for me (except the expression shoud read positiveFlags & ~negativeFlags). Additionally it leads to a simple method of applying inherited styles. If we rewrite your example

1: Bold
2: -Bold -Italic
3: Italic 

as (no specific syntax...)

1: pos:{ Bold }   neg:{ none }
2: pos:{ none }   neg:{ Bold Italic }
3: pos:{ Italic } neg:{ none }

then effective styles are calculated with inheritance as (prevLevelStyle | pos) & ~neg, resulting in:

1: ({ none } | { Bold })   & ~{ none }        = { Bold }
2: ({ Bold } | { none })   & ~{ Bold Italic } = { none }
3: ({ none } | { Italic }) & ~{ none }        = { Italic }

as desired.

Tap answered 2/5, 2011 at 1:13 Comment(0)
C
0

If I'm not mistaken, you do not nesessary need to define negative flags, but use "positive" flags to unset them.

For example, this code can be used to unset Bold flag

Styles styles = Styles.Bold | Styles.Italic;
styles = styles ^ Styles.Bold;
Confederacy answered 4/4, 2011 at 10:20 Comment(2)
The thing is that I need to store the negative values somehow until they are used for the final calculation of the value.Retrogradation
The second line toggles Bold, doesn't always exclude it (in your specific example it does though). Better to styles &= ~Styles.Bold; in all cases, which always unsets it.Sextillion

© 2022 - 2024 — McMap. All rights reserved.