FlagUtil 1.0.1.1

dotnet add package FlagUtil --version 1.0.1.1
NuGet\Install-Package FlagUtil -Version 1.0.1.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FlagUtil" Version="1.0.1.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add FlagUtil --version 1.0.1.1
#r "nuget: FlagUtil, 1.0.1.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install FlagUtil as a Cake Addin
#addin nuget:?package=FlagUtil&version=1.0.1.1

// Install FlagUtil as a Cake Tool
#tool nuget:?package=FlagUtil&version=1.0.1.1

dotnet.FlagUtil

dotnet.FlagUtil is a helper library guided towards assisting with binary flag operations. Allowing for an object oriented approach to binary flags it enables easy method calls for modifying and checking flags.

dotnet.FlagUtil is open source under the MIT licence.

Installation

The only dependancy for dotnet.FlagUtil is dotnetcore2.0.

Nuget

dotnet.FlagUtil is available as a NuGet package here: https://www.nuget.org/packages/FlagUtil/1.0.0

.dll

A pre-build .dll for dotnet.FlagUtil is available https://github.com/Polymeristic/dotnet.FlagUtil/tree/master/lib

Source

Download the repo and build using Visual Studio.

Usage

Using dotnet.FlagUtil is painlessly simple. It can be used with an Enum based approach or using long. We will be using the below example enum throughout the documentation.

public enum Status {
    ONLINE = 0b0001,
    OFFLINE = 0b0010,
    PROCESSING = 0b0100,
    FAILED = 0b1000
}

Creating a Flag

To create a flag you need to provide the Flag with a base value, to do so you can use either a; long, Flag or Enum - all can be parsed into a Flag. Usefully, the library supports unlimited arguments on almost all it's functions. If multiple arguments are detected it will automatically merge those flags into a single flag, as shown below.

public static void Main() {
    // Assignment using an Enum possible,
    // equiv. to 0b0001
    Flag f1 = new Flag(Status.ONLINE);
    
    // Equiv. to 0b0101
    Flag f2 = new Flag(Status.ONLINE,
                       Status.PROCESSING);
                       
    // You can also assign using any unsigned numerical type,
    // in this case f3 and f4 are equal
    Flag f3 = new Flag(0b0100);
    Flag f4 = new Flag(4);

    // And finally you can copy or compound flags using
    Flag f5 = new Flag(f1, f3);
    // Which would be equiv. to 0b0101
}

Flag Modification Operations

Merging Indicators

Merging a flag essentialy means adding a new indicator to the existing flag, in binary terms it is like an 'OR' operator. It would look like such 0010 | 0100 = 0110. Merging can be done either through methods or on initialization, as the initializer supports multiple parameters. An example of initialization merging would be:

// Has merged two flags into one
Flag status = new Flag(Status.ONLINE,
                       Status.PROCESSING);

Onced merged, you can use the == operator (or other equality operators) to check for the indicators contained within the overall flag. You can also merge additional indicators after the flag has been initialised, using our variable status we defined above, we can add a new indicator:

status += Status.FAILED;

As you can see the + operator can be used to add new indicators to a flag. Likewise, the - operator will remove indicators from a flag. See more about this in the Removing Indicators section.

You can also use the Flag.Merge(x, ..) method to merge more indicators, as such:

status.Merge(Status.FAILED, Status.OFFLINE);
Removing Indicators

As merging adds indicators, removing indicators will take them away. This can be visualised as a little bit more complicated of a binary expression, to remove 0010 from 0110 we can represent this as 0110 & ~0010. The removal of indicators can be done either by using the method Flag.Remove(x, ..) or by using the - operator.

In the below demonstration we remove the ONLINE and PROCESSING flags and replace them with OFFLINE and ERROR.

// Has merged two flags into one
Flag status = new Flag(Status.ONLINE,
                       Status.PROCESSING);

status -= Status.ONLINE;
status -= Status.PROCESSING;
status += Status.OFFLINE;
status += Status.ERROR;

This can be done in a cleaner way however, using the Flag.Remove(x, ..) and Flag.Merge(x, ..) methods.

// Has merged two flags into one
Flag status = new Flag(Status.ONLINE,
                       Status.PROCESSING);

status.Remove(Status.ONLINE, Status.PROCESSING);
status.Merge(Status.OFFLINE, Status.ERROR)
Bit-flip

In some, admittedly odd, circumstances you can flip all indicators in the flag by using either the ! or ~ operators, or Flag.Reverse(). Doing so will bit-flip all indicators, meaning 0011 would turn into 1100.

Other binary operators

Other binary operators such as bit-shifting have not been included due to fear of unnessicary bloat. However if you do wish to edit the flag's underlying value you can access it via the Value property.

Flag status = new Flag(Status.ONLINE);
status.Value = status.Value << 1;

Flag Equality

Flag equality in dotnet.FlagUtil isn't exactly what it would seem at first glance. Some assumptions were made around it's usage in order to be better suited to it's job, as such, it may not seem obvious at first as to the meaning of some operators.

Checking for flag indicators

The == operator is perhaps the most confusing as in our case it doesn't explicitly mean 'is x is equals to y?'. In dotnet.FlagUtils, the equals operator means 'is y is contained in x' - note the flip! Doing things this way means we can easy check for flag indicators.

Say we want to create a flag currentStatus, we would initialise it as such:

Flag currentStatus = new Flag(Status.ONLINE, Status.PROCESSING);

At present the flag is equivelant to the binary expression 0b0101, so, if we wish to check if this flag has the Status.ONLINE (equiv. to 0b0001) indicator all we need to do is:

if (currentStatus == Status.ONLINE) {
    // do something
}

As you can see the == operator does not mean 'x is equals to y' but instead means 'y is contained within x'. If we did need to check for an exact match we need to use the helper function Flag.MatchExact(x, ..)

In addition to using the == operator you can also use Flag.Match(x, ..) - these methods are functionally identical, however, Flag.Match(x, ..) supports multiple parameters. As such it will merge them into a single flag then check that against the subject. An example of this in our scenario would be:

if (currentStatus.Match(Status.OFFLINE, Status.PROCESSING)) {
   // would return TRUE because currentStatus has the Status.PROCESSING flag set. And since it 
   // contains Status.PROCESSIG it will return TRUE, even though Status.OFFLINE is not present.
}
Checking for exact flag matches

If you wish to check if two flags are exactly identical you will need to use the method Flag.MatchExact(x, ..). Yet again this method supports multiple parameters, these will be merged in the same way as the Flag.Match(x, ..) method.

Unline the Flag.Match(x, ..) and == methods, the Flag.MatchExact(x, ..) method does mean 'is x equals to y'. Again using the scenario of:

Flag currentStatus = new Flag(Status.ONLINE, Status.PROCESSING);

Here is an example of using the exact match method:

if (currentStatus.MatchExact(Status.ONLINE, Status.PROCESSING, Status.FAILED)) {
    // this code will NOT run
} else 
if (currentStatus.MatchExact(Status.ONLINE, Status.PROCESSING)) {
    // this code will run
}

String Representation

The Flag class implements ToString() in a way that it will convert it's flag value into the binary representation of the flag. This was done to ensure ease of idenficiation. As such

new Flag(Status.ONLINE, Status.PROCESSING).ToString()

Would output "0101"

HashCode

Due to the nature of a flag the hash code is simply equal to the flag's value. This means hash tables can be produced based on combined flag indicators. dawd

Feedback

For any feedback feel free to add to the Issues panel in the Github repo, or message me directly.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.1.1 529 3/2/2020
1.0.1 456 3/2/2020
1.0.0 439 3/2/2020