Extension method to convert Flags to IEnumerable<Enum> and conversely (C#) - c#

I spent a couple hours trying to figure out a generic way of converting an Enum mask to an array of Enum values and, conversely, an array of Enum values to its Enum mask.
Writing an extension method to do so was a bit of a pain so I just wanted to share my solution in case it could help someone. I'm sure it could be improved but, here it is!

The extension method below returns a mask from a list of Enum values.
public static T ToMask<T>(this IEnumerable<T> values) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
throw new ArgumentException("T must be an enumerated type.");
int builtValue = 0;
foreach (T value in Enum.GetValues(typeof(T)))
{
if (values.Contains(value))
{
builtValue |= Convert.ToInt32(value);
}
}
return (T)Enum.Parse(typeof(T), builtValue.ToString());
}
The extension method below returns a list of Enum values from a mask.
public static IEnumerable<T> ToValues<T>(this T flags) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
throw new ArgumentException("T must be an enumerated type.");
int inputInt = (int)(object)(T)flags;
foreach (T value in Enum.GetValues(typeof(T)))
{
int valueInt = (int)(object)(T)value;
if (0 != (valueInt & inputInt))
{
yield return value;
}
}
}
Note that:
Generic constraints in c# (where T : ...) cannot restrict T to an Enum
These methods do not check whether the Enum has the [Flags] attribute (could not figure that out)
Usage:
[Flags]
public enum TestEnum : int
{
None = 0,
Plop = 1,
Pouet = 2,
Foo = 4,
Bar = 8
}
To mask:
TestEnum[] enums = new[] { TestEnum.None, TestEnum.Plop, TestEnum.Foo };
TestEnum flags = enums.ToMask();
TestEnum expectedFlags = TestEnum.None | TestEnum.Plop | TestEnum.Foo;
Assert.AreEqual(expectedFlags, flags);
To values:
TestEnum flags = TestEnum.None | TestEnum.Plop | TestEnum.Foo;
TestEnum[] array = flags.ToValues().ToArray();
TestEnum[] expectedArray = new[] { TestEnum.Plop, TestEnum.Foo };
CollectionAssert.AreEqual(expectedArray, array);

I needed a simple solution for converting the opposite direction (instead of having to include the extension), so here's a Linq solution to turn an IEnumerable of your enum into a flagged enum:
MyEnum e = MyEnumList.Aggregate((MyEnum)0, (a,b) => a |= b);

Related

Check if flag contains any value of other flag

I would like compare two flags and see if they have any common value.
I'ld like having an extension method as weel in order to "speed up" coding (I'm going to use it often and on various Enum types). How can I?
This code tell me:
operator '&' cannot be applied to operands of type enum and enum
public enum Tag
{
Value1 = 1,
Value2 = 2,
Value3 = 4,
Value4 = 8,
Value5 = 16
}
public static class FlagExt
{
public static bool HasAny(this Enum me, Enum other)
{
return (me & other) != 0;
}
}
public class Program
{
public static void Main()
{
Tag flag1 = Tag.Value1 | Tag.Value2 | Tag.Value3;
Tag flag2 = Tag.Value2 | Tag.Value3 | Tag.Value4;
Console.WriteLine(flag1.HasAny(flag2)); // it should returns true. flag1.HasFlag(flag2) returns false.
}
}
I tried this as well:
return (((int)me) & ((int)other)) != 0;
but it raises the error:
Cannot convert type 'System.Enum' to 'int'
As per this answer (How to convert from System.Enum to base integer?)
You will need to wrap this code with an exception handler or otherwise ensure that both enums hold an integer.
public static class FlagExt
{
public static bool HasAny(this Enum me, Enum other)
{
return (Convert.ToInt32(me) & Convert.ToInt32(other)) != 0;
}
}
If you want a very generic HasAny extension for enums you could do the following. I've tested that this works with all the different underlying types that an enum can be. Also, if you are checking for flags you should probably have the [Flags] attribute decorating your enum, so this checks that the enums being checked have that attribute.
public static class FlagExtensions
{
public static bool HasAny(this Enum enumLeft, Enum enumRight)
{
if (enumLeft.GetType() != enumRight.GetType())
throw new ArgumentException("enum types should be the same");
if (!enumLeft.GetType().IsDefined(typeof(FlagsAttribute), inherit: false))
throw new ArgumentException("enum type should have the flags attribute");
dynamic enumLeftValue = Convert.ChangeType(enumLeft, enumLeft.GetTypeCode());
dynamic enumRightValue = Convert.ChangeType(enumRight, enumRight.GetTypeCode());
return (enumLeftValue & enumRightValue) != 0;
}
}
I tried this as well:
return (((int)me) & ((int)other)) != 0;
but it raises the error:
Cannot convert type 'System.Enum' to 'int'
Enums always implement IConvertible and IConvertible has 'ToInt32'. So you could write it like this:
public static class FlagExt
{
public static bool HasAny<TEnum>(this TEnum me, TEnum other)
where TEnum : Enum, IConvertible
{
return (me.ToInt32(null) & other.ToInt32(null)) != 0;
}
}

Before C# 7.3 arrives how to get generic method constrained to Enums to compile/work

C# is cool and will allow comparison of Enums and then convert to strings. I already got from SO some code to enumerate the individual items of an Enum (top method in class below). Then, in second method (that I wrote) I managed to convert to string when an enum matches a given value.
The third method, I would like some help with. Given a flag based enum where the given value is in fact many values AND'ed together, I want to atomise the values and convert to a List<string>. If I had C# 7.3 then I think limiting the <T> to an enum might help the compilation. Until then, how can achieve the goal of decomposing a flag enum into atomic values converted to strings.
public static class EnumUtil
{
// JaredPar https://stackoverflow.com/questions/972307/can-you-loop-through-all-enum-values#answer-972323
public static IEnumerable<T> GetValues<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
// S Meaden
public static string MatchFirst<T> (T matchThis)
{
T[] values = (T[])EnumUtil.GetValues<T>();
foreach (T val in values)
{
if (matchThis.Equals(val))
{
return val.ToString();
}
}
return "";
}
// S Meaden
// C# 7.3 https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters#enum-constraints
public static List<string> MatchFlags<T> (T matchThis) where T : System.Enum
{
List<string> flags = new List<string>();
T[] values = (T[])EnumUtil.GetValues<T>();
long lMatchThis = (long)matchThis;
foreach (T val in values)
{
long lVal = val;
//if (lMatchThis & lVal)
if (matchThis & val)
{
flags.Add(val.ToString());
}
}
return flags;
}
}
Can't get past C# 7.2.
Use where T : struct and throw an ArgumentException if not a System.Enum:
public static List<string> MatchFlags<T> (T matchThis) where T : struct
{
if (!(matchThis is System.Enum)) {
throw new ArgumentException("Gotta be an enum");
}
//etc.
}
If you have a flags enum and you want to convert it into a List<string>, do something like this:
matchThis.ToString().Split(',').ToList();

C# - Receive string and use it as an enum key [duplicate]

I have an enum type like this as an example:
public Enum MyEnum {
enum1, enum2, enum3 };
I'll read a string from config file. What I need is to parse the string to MyEnum type or null or not defined. Not sure if the following code will work (sorry for not having access to my VS right now):
// example: ParseEnum<MyEnum>("ENUM1", ref eVal);
bool ParseEnum<T>(string value1, ref eVal) where T : Enum
{
bool bRet = false;
var x = from x in Enum.GetNames(typeof(T)) where
string.Equals(value1, x, StringComparison. OrdinalIgnoreCase)
select x;
if (x.Count() == 1 )
{
eVal = Enum.Parse(typeof(T), x.Item(0)) as T;
bRet = true;
}
return bRet;
}
Not sure if it is correct or there is any other simple way to parse a string to a MyEnum value?
What about something like:
public static class EnumUtils
{
public static Nullable<T> Parse<T>(string input) where T : struct
{
//since we cant do a generic type constraint
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Generic Type 'T' must be an Enum");
}
if (!string.IsNullOrEmpty(input))
{
if (Enum.GetNames(typeof(T)).Any(
e => e.Trim().ToUpperInvariant() == input.Trim().ToUpperInvariant()))
{
return (T)Enum.Parse(typeof(T), input, true);
}
}
return null;
}
}
Used as:
MyEnum? value = EnumUtils.Parse<MyEnum>("foo");
(Note: old version used try/catch around Enum.Parse)
private enum MyEnum
{
Enum1 = 1, Enum2 = 2, Enum3 = 3, Enum4 = 4, Enum5 = 5, Enum6 = 6,
Enum7 = 7, Enum8 = 8, Enum9 = 9, Enum10 = 10
}
private static Object ParseEnum<T>(string s)
{
try
{
var o = Enum.Parse(typeof (T), s);
return (T)o;
}
catch(ArgumentException)
{
return null;
}
}
static void Main(string[] args)
{
Console.WriteLine(ParseEnum<MyEnum>("Enum11"));
Console.WriteLine(ParseEnum<MyEnum>("Enum1"));
Console.WriteLine(ParseEnum<MyEnum>("Enum6").GetType());
Console.WriteLine(ParseEnum<MyEnum>("Enum10"));
}
OUTPUT:
//This line is empty as Enum11 is not there and function returns a null
Enum1
TestApp.Program+MyEnum
Enum10
Press any key to continue . . .
This is an old question, but now .NET 4.5 has Enum.TryParse<TEnum>().
I have a TryParseName method in UnconstrainedMelody, a library for delegate and enum utility methods which uses "inexpressible" constraints via some postbuild trickery. (Code using the library doesn't need a postbuild, just to be clear.)
You would use it like this:
Foo foo;
bool parsed = Enums.TryParseName<Foo>(name, out foo);
I don't currently have a case-insensitive version, but I could easily introduce one if you wanted. Note that this doesn't try to parse numbers e.g. "12" like the built-in version does, nor does it try to parse comma-separated lists of flags. I may add the flags version later on, but I can't see much point in the numeric version.
This is done without boxing and without execution time type checking. Having the constraint is really handy :)
Please let me know if you'd find a case-insensitive parse useful...
If you're using .NET 3.5 (or even 2.0, if you trim out the extension method), I've had great luck with the techniques in this article:
Enumerations and Strings - Stop the Madness!
EDIT: Domain is gone and is now a link farm. I pulled the code (slightly modified and added to over time) from our codebase at work, which you can now find here:
https://gist.github.com/1305566
You can use TryParse if you want to avoid using try/catch.
MyEnum eVal;
if (Enum.TryParse("ENUM2", true, out eVal)){
// now eVal is the enumeration element: enum2
}
//unable to parse. You can log the error, exit, redirect, etc...
I modified the selected answer a little bit. I hope you like it.
public static class EnumUtils
{
public static Nullable<T> Parse<T>(string input) where T : struct
{
//since we cant do a generic type constraint
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Generic Type 'T' must be an Enum");
}
int intVal;
if (!string.IsNullOrEmpty(input) && !int.TryParse(input, out intVal))
{
T eVal;
if (Enum.TryParse(input, true, out eVal))
{
return eVal;
}
}
return null;
}
}
I have just combined the syntax from here, with the exception handling from here, to create this:
public static class Enum<T>
{
public static T Parse(string value)
{
//Null check
if(value == null) throw new ArgumentNullException("value");
//Empty string check
value = value.Trim();
if(value.Length == 0) throw new ArgumentException("Must specify valid information for parsing in the string", "value");
//Not enum check
Type t = typeof(T);
if(!t.IsEnum) throw new ArgumentException("Type provided must be an Enum", "TEnum");
return (T)Enum.Parse(typeof(T), value);
}
}
You could twiddle it a bit to return null instead of throwing exceptions.
To return Enum by string, if contains:
public static T GetEnum<T>(string s)
{
Array arr = Enum.GetValues(typeof(T));
foreach (var x in arr)
{
if (x.ToString().Contains(s))
return (T)x;
}
return default(T);
}

Custom generic SetFlag / UnsetFlag extension methods

In my childish naïvety, I decided to build generic SetFlag and UnsetFlag extension methods for Enums, so no one has to read and reread and rereread the bitwise operators all over my code:
public static void SetFlag<T>(this T en, T flag) where T : Enum {
en |= flag;
}
and
public static void UnsetFlag<T>(this T en, T flag) where T : Enum
{
en &= ~flag;
}
Now I get the errors that operator |= is not applicable to types T and T and operator ~ is not applicable to type T.
I think that I have to change T to the type "Enum with HasFlags". Is this the true root of the problem, and how would I change that?
Here are my methods. As I said in the comments to the question, I strongly discourage from using this methods in production code:
public static T SetFlag<T>(this T en, T flag) where T : struct, IConvertible
{
int value = en.ToInt32(CultureInfo.InvariantCulture);
int newFlag = flag.ToInt32(CultureInfo.InvariantCulture);
return (T)(object)(value | newFlag);
}
public static T UnsetFlag<T>(this T en, T flag) where T : struct, IConvertible
{
int value = en.ToInt32(CultureInfo.InvariantCulture);
int newFlag = flag.ToInt32(CultureInfo.InvariantCulture);
return (T)(object)(value & ~newFlag);
}
Usage:
[Flags]
public enum Flags
{
None = 0, A = 1, B = 2, C = 4
}
Flags flags = Flags.A.SetFlag(Flags.C);
flags = flags.UnsetFlag(Flags.C);
As you can see I made use of it, that every enum implements IConvertible. So I defined extension methods on this interface which also provides a handy method for converting the value of the enum to an int. A side effect of this is that you can use this methods for every other type which implements this interface. So you could abuse this methods for something like this:
int a = 0;
a = a.SetFlag(5); // a == 5
a = a.UnsetFlag(4); // a == 1

C# How to check an enum value is passed in a parameter?

I have a method which accepts an enum as an argument:
[Flags]
public enum MyEnum
{
A = 1,
B = 2,
C = 3
}
public class MyClass
{
public MyEnum myEnum;
}
public bool MyMethod(MyClass class, MyEnum enumParam)
{
// Here I want to check if object class contains some enum values passed as an argument
// Something like: if(class.myEnum 'contains-one-of-the-items-of enumParam)
}
public void Test()
{
Myclass class = new MyClass() { myEnum = MyEnum.A };
MyMethod(class, MyEnum.A | MyEnum.B);
}
I want to check if an object contains one of the enum values which are passed in the method as an argument.
As your using flags, this may help you with checking if an enum value has been set:
What does the [Flags] Enum Attribute mean in C#?
You can write it like this
public bool MyMethod(MyClass class, MyEnum enumParam)
{
if( (enumParam & MyEnum.A) != 0 ){
...
}
if( (enumParam & MyEnum.B) != 0 ){
...
}
}
I changed enum to enumParam to not conflict with the enum keyword.
There is also a problem with your implementation since you have the values 1,2,3 for A,B,C. This way you can't differentiate between A+B=3 and C=3. A should be 1, B should be 2 and C should be 4 (D should be 8 and so on)
EDIT
Edit due to OP's comment.
public bool MyMethod(MyClass class, MyEnum enumParam)
{
return Enum.IsDefined(typeof(MyEnum), enumParam);
}
If you want to see if any of the values passed in the parameter are in the class's myEnum field, you can write:
public bool MyMethod(MyClass class, MyEnum enum)
{
// Here I want to check if object class contains some enum values passed as an argument
// Something like: if(class.myEnum 'contains-one-of-the-items-of enum)
return (this.myEnum & enum) != 0;
}
This does a logical "AND" of the bit flags and will return true if any one of the flags in enum is set in myEnum.
If you want to ensure that all the flags are set, then you can write:
return (this.myEnum & enum) == this.myEnum;
Also, read the response by #Øyvind Bråthen carefully. In order for [Flags] to work, you need to ensure that your enum values are powers of 2.
Change your enum like this :
public enum MyEnum
{
A = 2,
B = 4,
C = 8
}
and your method is as simple as :
public bool MyMethod(MyClass aClass, MyEnum aEnum)
{
return (aClass.myEnum & aEnum) != 0;
}
Best regards
In C# 4.0 you can easily use Enum.HasFlag method. You can take a look at this question to get other solutions including C# 3.5 and previous versions.

Categories