Bitmask'ed Int to Enum[] or Int[]? c# - c#

I have an enum that looks like this:
enum foo{
a=0,
b=1,
c=2,
d=4
}
Building the flag / bitmask is fine, but is it possible to do something like
int i = 3;
var bar = Enum.Split(foo,i);
Resulting in something like
bar = foo[]{a, b,c};
Thanks.

Try the following
public static IEnumerable<T> Split<T>(int value) {
foreach (object cur in Enum.GetValues(typeof(T))) {
var number = (int)(object)(T)cur;
if (0 != (number & value)) {
yield return (T)cur;
}
}
}
With this you can now write
int i = 3;
IEnumerable<foo> e = Split<foo>(i);
Note: This only works on enum values which derive from int (the default setting). It's also not entirely type safe as T can't be constrained to only enum values (nothing to do about that though)

You can use the FlagsAttribute on the enum and get lots of the functionality for free (no need to work at the bit level).
MSDN describes the attribute as:
Indicates that an enumeration can be treated as a bit field; that is, a set of flags.

The [FlagsAttribute] allows you to extract all of the valid values.
http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx

Try this:
TEnum[] EnumSplit<TEnum>(int mask)
{
List<TEnum> values = new List<TEnum>();
foreach(int enumValue in Enum.GetValues(typeof(TEnum)))
{
if(mask & enumValue == enumValue)
values.Add((TEnum)enumValue);
}
return values.ToArray();
}
Call it like this:
var bar = EnumSplit<foo>(i);
Preferably, you want to change it to return IEnumerable<TEnum> instead of TEnum[].

You could do this with a method which pulls the values from the Enum you pass:
public static T[] EnumSplit<T>(int value) where T : struct
{
// Simplified as Enum.GetValues will complain if T is not an enum
// However, you should add a check to make sure T implements FlagAttribute
return (from vv in Enum.GetValues(typeof(T))
where ((int)vv & value) != 0
select (T)vv).ToArray();;
}

var flags = Enum.GetValues(typeof (/* YourEnumType */))
.Cast</* YourEnumType */>()
.Select(v => enumValue.HasFlag(v))
.ToArray();

Related

How to get enum order?

If I have enum:
public enum ImportState : byte
{
None = 0,
ImportedWithChanges = 44,
AwaitingApproval = 45,
Removing = 66,
Revalidating = 99,
};
How to get enum order?
For example:
GetOrder(ImportState.None)
Should return 1(first in order)
GetOrder(ImportState.AwaitingApproval )
Should return 3 (third in order)
here is the missing method GetOrder
public static int GetOrder(ImportState State)
{
return Enum.GetValues(typeof(ImportState)).Cast<ImportState>().Select((x, i) => new { item = x, index = i }).Single(x => x.item == State).index;
}
As other noticed, Enum.GetValues() returns the values of an enum sorted by value. Perhaps this isn't what you wanted... So, using a little reflection:
public class EnumOrder<TEnum> where TEnum : struct
{
private static readonly TEnum[] Values;
static EnumOrder()
{
var fields = typeof(Values).GetFields(BindingFlags.Static | BindingFlags.Public);
Values = Array.ConvertAll(fields, x => (TEnum)x.GetValue(null));
}
public static int IndexOf(TEnum value)
{
return Array.IndexOf(Values, value);
}
}
Example of use:
public enum Values
{
Foo = 10,
Bar = 1
}
int ix = EnumOrder<Values>.IndexOf(Values.Bar); // 1
Note that the C# specifications aren't clear if the "source code" ordering of an enum is maintained in the compiled program... At this time the C# compiler seems to maintain it, but there is no guarantee in the future...
The only two references I've found are:
Forward declarations are never needed in C# because, with very few exceptions, declaration order is insignificant
and
Declaration order for enum member declarations (§14.3) is significant when constant-expression values are omitted.
So as written, for the example I gave, the ordering is undefined and depends on the C# compiler!
Enumerating the enum values, casting to an IEnumerable, converting to a List. This it is a simple matter of using IndexOf().
Note that for this to work, the enum must be declared in increasing order.
namespace ConsoleApplication1
{
using System;
using System.Linq;
class Program
{
public enum ImportState : byte
{
None = 0,
ImportedWithChanges = 44,
AwaitingApproval = 45,
Removing = 66,
Revalidating = 99,
}
static void Main(string[] args)
{
Console.WriteLine(GetOrder(ImportState.None));
Console.WriteLine(GetOrder(ImportState.AwaitingApproval));
}
public static int GetOrder(ImportState state)
{
var enumValues = Enum.GetValues(typeof(ImportState)).Cast<ImportState>().ToList();
return enumValues.IndexOf(state) + 1; // +1 as the IndexOf() is zero-based
}
}
}
1
3
Press any key to continue . . .
Sth. like this?
int i = 0;
foreach (ImportState state in Enum.GetValues(typeof(ImportState)))
{
i++;
if (state == myState) return i;
}
However there is no real use for this, as enums do not provide an indexed enumeration in themselfes. They represent a value which is more what you´re probably after.
You can use this LINQ query:
int position = Enum.GetValues(typeof(ImportState)).Cast<ImportState>()
//.OrderBy(impState => (int)impState)
.TakeWhile(impState => impState != ImportState.None)
.Count() + 1;
It orders by the int-value of the enum-value, then it takes all until the searched value and counts them. I have omitted the OrderBy since Enum.GetValues automatically returns the order according to their int-value.
MSDN:
The elements of the array are sorted by the binary values of the
enumeration constants
Instead of using the order, you would be better to make better use of the flags. Consider the following
public enum ImportState : byte
{
None = 0,
ImportedWithChanges = 2,
AwaitingApproval = 4,
Removing = 6,
Revalidating = 8,
};
(double)state / Enum.GetValues(typeof(ImportState)).Cast<byte>().Max()
Example
Enums don't really have any sense of ordering, using the above probably still isn't perfect but it doesn't involve a made up order.
What about this Solution?
var result = from r in Enum.GetValues<ImportState>()
let expression =
r == ImportState.Revalidating
? 0
: r == ImportState.AwaitingApproval
? 1
: r == ImportState.Removing
? 2
: r == ImportState.ImportedWithChanges
? 3
: 4
orderby expression ascending
select r.ToString();
Console.WriteLine(string.Join(", ", result));
Output: Revalidating, AwaitingApproval, Removing, ImportedWithChanges, None

How to get numeric position of an enum in its definition list?

I need to get the numeric position of an enum in its definition.
Consider the following enum - it is used for bit fields but the status names
would be useful if they had the values on the right that I have commented.
[Flags]
public enum StatusFlags
{
None = 0, // 0 -- these commented indexes are the numbers I also would like
Untested = 1, // 1 to associate with the enum names.
Passed_Programming = 2, // 2
Failed_Programming = 4, // 3
// ... many more
}
I have created a static method as follows, which works for what I want.
public static int GetStatusID(this StatusFlags flag)
{
int i = 0;
foreach (StatusFlags val in Enum.GetValues(typeof(StatusFlags)))
{
if (flag == val) break;
i++;
}
return i;
}
It is used like this:
StatusFlags f = StatusFlags.Failed_Programming;
// I want the position i.e value of 3 not the value the enum is associated with i.e 4
int Index = f.GetStatusID();
Is there is a better way to do this?
How about using attributes on your enum? Something like this:
[Flags]
public enum StatusFlags
{
[Index=0]
None = 0,
[Index=1]
Untested = 1,
[Index=2]
Passed_Programming = 2,
[Index=3]
Failed_Programming = 4,
// ... many more
}
Then you can the index value of your enum like this:
var type = typeof(StatusFlags);
var statusFlag = type.GetMember(StatusFlags.Untested.ToString());
var attributes = statusFlag [0].GetCustomAttributes(typeof(IndexAttribute),false);
var index = int.Parse(((IndexAttribute)attributes[0]).Index); //if you need an int value
A deleted answer here suggested something that resembled
public static int GetStatusID(this StatusFlags flag)
{
return Array.IndexOf(Enum.GetValues(typeof(StatusFlags)), flag);
}
and was just missing the syntactical point that IndexOf is a static function in the Array class, not an extension method. I like it though for brevity.
You could do this:
public static int GetStatusID(this StatusFlags flag)
{
return
Enum
.GetValues(typeof(StatusFlags))
.Cast<StatusFlags>()
.Select((f, n) => new { f, n })
.Where(fn => fn.f == flag)
.Select(fn => fn.n)
.DefaultIfEmpty(0)
.First();
}
How about just using math? He says the flags go up in powers of 2
int GetStatusID(this StatusFlags flag)
{
if (((int)flag) == 0) return 0;
return (Math.Log((double)flag) / Math.Log(2D)) + 1;
}
If each flag has only 1 bit set like that then the index is just Math.Log2((int)flag) + 1. However Math.Log2 is a floating-point operation and is very slow so don't use it
If you're using .NET Core then there are BitOperations.Log2 and BitOperations.TrailingZeroCount which map directly to hardware instructions like TZCNT/BSF in x86 or CLZ in ARM, hence are much more efficient and the result is like this
public static int GetStatusID(this StatusFlags flag)
{
if ((int)flag == 0)
return 0;
return BitOperations.Log2((int)flag);
// or return BitOperations.TrailingZeroCount((int)flag) + 1;
}
If you're using an older .NET framework then calculate see the way to calculate integer log2 quickly in these questions
What's the quickest way to compute log2 of an integer in C#?
Fastest implementation of log2(int) and log2(float)
Fast way of finding most and least significant bit set in a 64-bit integer

List all bit names from a flag Enum

I'm trying to make a helper method for listing the names of all bits set in an Enum value (for logging purposes). I want have a method that would return the list of all the Enum values set in some variables. In my example
[Flag]
Enum HWResponse
{
None = 0x0,
Ready = 0x1,
Working = 0x2,
Error = 0x80,
}
I feed it 0x81, and it should provide me with a IEnumerable<HWResponse> containing {Ready, Error}.
As I didn't find a simpler way, I tried to write the code below, but I can't make it compile.
public static IEnumerable<T> MaskToList<T>(Enum mask)
{
if (typeof(T).IsSubclassOf(typeof(Enum)) == false)
throw new ArgumentException();
List<T> toreturn = new List<T>(100);
foreach(T curValueBit in Enum.GetValues(typeof (T)).Cast<T>())
{
Enum bit = ((Enum) curValueBit); // Here is the error
if (mask.HasFlag(bit))
toreturn.Add(curValueBit);
}
return toreturn;
}
On this version of the code, the compiler complains that it can't cast T to Enum.
What did I do wrong? Is there a better (simpler) way to do this? How could I make the cast?
Also, I tried to write the method as
public static IEnumerable<T> MaskToList<T>(Enum mask) where T:Enum
but Enum is of a special type that forbids the 'where' syntax (Using C# 4.0)
Here's a simple way to write it using LINQ:
public static IEnumerable<T> MaskToList<T>(Enum mask)
{
if (typeof(T).IsSubclassOf(typeof(Enum)) == false)
throw new ArgumentException();
return Enum.GetValues(typeof(T))
.Cast<Enum>()
.Where(m => mask.HasFlag(m))
.Cast<T>();
}
If your desired end result is a string list of names, just call mask.ToString().
What would you do if the enum were defined like this:
[Flags]
enum State
{
Ready = 1,
Waiting = 2,
ReadyAndWaiting = 3
}
As to resolving the compiler error, this should do it:
Enum bit = (Enum)(object)curValueBit;
Jon Skeet has a project called unconstrained melody that allows you to add the enum constraint, after compilation, by rewriting the IL. This works because the CLR supports such a constraint, even though C# does not.
Another thought: It will be more efficient to cast the return value of GetValues directly to T[]:
foreach(T curValueBit in (T[])Enum.GetValues(typeof (T)))
Building on Gabe's answer I came up with this :
public static class EnumHelper<T>
where T : struct
{
// ReSharper disable StaticFieldInGenericType
private static readonly Enum[] Values;
// ReSharper restore StaticFieldInGenericType
private static readonly T DefaultValue;
static EnumHelper()
{
var type = typeof(T);
if (type.IsSubclassOf(typeof(Enum)) == false)
{
throw new ArgumentException();
}
Values = Enum.GetValues(type).Cast<Enum>().ToArray();
DefaultValue = default(T);
}
public static T[] MaskToList(Enum mask, bool ignoreDefault = true)
{
var q = Values.Where(mask.HasFlag);
if (ignoreDefault)
{
q = q.Where(v => !v.Equals(DefaultValue));
}
return q.Cast<T>().ToArray();
}
}
I organized things a bit differently, namely I put the type check (i.e.: the verification that T is really an enumeration) and the obtaining of the enum values in the static constructor so this is done only once (this would be a performance improvement).
Another thing, I added an optional parameter so you can ignore the typical "zero" / "None" / "NotApplicable" / "Undefined" / etc value of the enumeration.
I spent some time on searching how to convert Flags enum value to List.
I have found pretty simple solution, maybe it will help someone.
[Flags]
public enum Tag
{
None = 0,
Stablecoin = 1,
NativeTokens = 2,
Dex = 4
}
var values = Tag.Stablecoin | Tag.Dex;
var str = values.ToString(); //"Stablecoin, Dex"
var list = uniqueNftTagsV2.Split(", "); //{"Stablecoin","Dex"}
What if just do something like this:
public static IEnumerable<T> MaskToList<T>(Enum mask)
{
if (typeof(T).IsSubclassOf(typeof(Enum)) == false)
throw new ArgumentException();
List<T> toreturn = new List<T>(100);
foreach(T curValueBit in Enum.GetValues(typeof (T)).Cast<T>())
{
Enum bit = (curValueBit as Enum); // The only difference is actually here,
// use "as", instead of (Enum) cast
if (mask.HasFlag(bit))
toreturn.Add(curValueBit);
}
return toreturn;
}
As the as has not compile time check. Compiler here just "believes" you, hoping that you know what you're doing, so the compile time error not raised.

How do I determine if an Enum value has one or more of the values it's being compared with?

I've got an Enum marked with the [Flags] attribute as follows:
[Flags]
public enum Tag : int
{
None = 0,
PrimaryNav = 1,
HideChildPages = 2,
HomePage = 4,
FooterLink = 8
}
On sitemapnodes in my sitemap I store the int value for the tags combination as an attribute.
What I need to do is check if a node has any one of one or more tags, e.g. Tag.PrimaryNav | Tag.HomePage.
I'm struggling with the necessary boolean logic to determine if an Enum value has one or more of the values it's being compared with.
Apologies if this isn't clear. I can provide more information if necessary.
You can do that by combining values with | and checking via &.
To check if the value contains either of the tags:
if ((myValue & (Tag.PrimaryNav | Tag.HomePage)) != 0) { ... }
The | combines the enums you're testing (bitwise) and the & tests via bitwise masking -- if the result isn't zero, it has at least one of them set.
If you want to test whether it has both of them set, you can do that as well:
Tag desiredValue = Tag.PrimaryNav | Tag.HomePage;
if ((myValue & desiredValue) == desiredValue) { ... }
Here we're masking off anything we don't care about, and testing that the resulting value equals what we do care about (we can't use != 0 like before because that would match either value and here we're interested in both).
Some links:
The & Operator
The | Operator
You can use the HasFlag Method to avoid the need for the boolean logic,
Tag Val = (Tag)9;
if (Val.HasFlag(Tag.PrimaryNav))
{
Console.WriteLine("Primary Nav");
}
if(Val.HasFlag(Tag.HomePage))
{
Console.WriteLine("Home Page");
}
For bitwise (Flags) enums, an "any of" test is != 0, so:
const Tag flagsToLookFor = Tag.PrimaryNav | Tag.HomePage;
if ((node.Tag & flagsToLookFor) != 0) {
// has some cross-over with PrimaryNav or HomePage (and possibly others too)
}
var someEnumValue = Tag.PrimaryNav | Tag.HomePage;
To test if the enum contains a given value:
if ((someEnumValue & Tag.PrimaryNav) == Tag.PrimaryNav)
{
}
var tag = Tag.HideChildPages | Tag.PrimaryNav;
If ((tag & Tag.PrimaryNav) == Tag.PrimaryNav) {
// Tag.PrimaryNav set.
}
You could use Jon Skeet's Unconstrained Melody library:
var someEnumValue = Tag.PrimaryNav | Tag.HideChildPages;
someEnumValue.HasAny(Tag.PrimaryNav | Tag.HomePage); // Returns true
You can use this extension method on enum, for any type of enums:
public static bool IsSingle(this Enum value)
{
var items = Enum.GetValues(value.GetType());
var counter = 0;
foreach (var item in items)
{
if (value.HasFlag((Enum)item))
{
counter++;
}
if (counter > 1)
{
return false;
}
}
return true;
}
That's a classic Extension method:
public static bool HasFlag(this Enum val, Enum t)
{
return (Convert.ToUInt64(val) & Convert.ToUInt64(t)) != 0;
}

convert string[] to int?[]

how to convert a string array to nullable integer array.
Well, the two aspects are:
How do you convert an array from one type to another?
How do you convert a string to a nullable int?
The first is simple - you can use Array.ConvertAll, passing in an Converter delegate. There's the LINQ way as well (x.Select(...).ToArray()), but that's slightly less efficient if you know you've got an array to start with and you want an array out of the other end 1.
The string to int? is probably best done in a method. You can do it in an anonymous function, but in this particular case I'd use a separate method. I rarely like to have to declare variables in an anonymous function.
public static int? TryParseInt32(string text)
{
int value;
return int.TryParse(text, out value) ? value : (int?) null;
}
To answer the comment, yes you need the cast 2.
or without the conditional:
public static int? TryParseInt32(string text)
{
int value;
if (int.TryParse(text, out value))
{
return value;
}
else
{
return null;
}
}
Put them together like this:
string[] x = {"15", "10", "hello", "5" };
int?[] y = Array.ConvertAll(x, TryParseInt32);
1 Array.ConvertAll is more efficient than x.Select().ToArray() because it has more information. It can create the final array immediately - no resizing is ever required. Calling Enumerable.ToArray() (with the result of Select()) doesn't have the same information, so it effectively has to add the results to a List<T> (potentially resizing several times along the way) and then usually resize at the end as well. (It doesn't actually use List<T> but the concepts are the same.) It's definitely worth knowing about the Select/ToArray solution, but I don't think it's actually any more readable than ConvertAll in this case, so you might as well use the more efficient form.
2 The reason you need the cast in the conditional is because the compiler doesn't know what type of "null" you really mean - but it knows it can't convert from null to an int. The type of the conditional expression has to be either the type of the second operand or the type of the third operand, and the other one has to be implicitly convertibly. By forcing the third operand to be of type int? here everything is fine - because you can implicitly convert from int to int?. Note that the compiler doesn't take the way you're using the expression to try to work out the type. Another alternative is to use new int?() instead of null.
By parsing and using Linq:
string[] input = { "1", "3", "x" }
var result = input.Select(
s => { int i; return (int.TryParse(s, out i)) ? i : (int?) null; }).ToArray();
… but I grant that this is a bit cryptic. I wouldn’t use a lambda expression here. For clarity, this should belong to a proper function ParseNullableInt. Then you can call it like this:
var result = input.Select(ParseNullableInt).ToArray();
Edit: I removed the null/empty check because TryParse properly handles those cases by returning false.
string[] stringArray = ...;
int?[] nullableIntArray = Array.ConvertAll(stringArray,
s =>
{
int value;
if (!int.TryParse(s, out value))
return default(int?);
return (int?)value;
});
One option would be this (I'm presuming that you want nulls for the values that were not integer values):
public static class StringArrayExtension
{
public static int?[] ToNullableIntArray(this string[] array)
{
int?[] result = new int?[array.Length];
for (int index = 0; index < array.Length; index++)
{
string sourceValue = array[index];
int destinationValue;
if (int.TryParse(sourceValue, out destinationValue))
{
result[index] = destinationValue;
}
else
{
result[index] = null;
}
}
return result;
}
}
usage:
string[] source = { "hello", "1", "3.1415", "20", "foo" };
int?[] dest = source.ToNullableIntArray();
You need to use int.TryParse:
string[] s = { "123", "a", "45" };
int?[] result = new int?[s.Length];
for (int i = 0; i < s.Length; ++i)
{
int a;
if (int.TryParse(s[i], out a))
result[i] = a;
}
List<int?> ints = new List<int?>();
foreach (string str in strs)
{
int val;
if (int.TryParse(str, out val))
{
ints.Add(val);
}
else { ints.Add(null); }
}
return ints.ToArray();
An integer array can not be null. In fact every element in Integer Array will have "0" by default.
Regarding Conversion
Create an Integer array of the same length or an arraylist
int [] _arr=new int[strArray.length];
for(int i=0;i<strArray.length;i++]
{
if(String.IsNullOrEmpty(strArray[i]))
{
_arr[i]=0;
}
else
{
_arr[i]=int.Parse(strArray[i]);
}
}

Categories

Resources