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.
Related
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;
}
}
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
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);
I have the following enumeration:
public enum MyEnum
{
MyTrue,
MyFalse
}
And I'd like to eventually be able to automatically convert my enumeration to a boolean value, with a simple line like this:
MyEnum val = MyEnum.MyTrue;
bool IsThisTrue = val;
Currently, I have to do this:
bool IsThisTrue = val == MyEnum.MyTrue;
Is there some mechanism I can apply to my enumeration to allow for native enum->bool casting? I'm wondering if some variant of a typeconverter is what I need or not.
Thanks
Edit: There is a reason for my custom enumeration. Since this properties are all eventually bound to a property grid, we have mechanisms put in place to bind all of our custom enumerations to multi-lingual strings in resources files. We need all of the enum's we're using to be in a specific namespace, hence the "MyEnum" class.
That line would work only with an implicit static conversion operator (or maybe the more-confusing true() operator, but that is rarely seen in the wild). You cannot define operators on enums, so ultimately the answer is: no.
You could, however, write an extension method on MyEnum to return true or false.
static class MyEnumUtils {
public static bool Value(this MyEnum value) {
switch(value) {
case MyEnum.MyTrue: return true;
case MyEnum.MyFalse: return false;
default: throw new ArgumentOutOfRangeException("value");
// ^^^ yes, that is possible
}
}
}
then you can use bool IsThisTrue = val.Value();
Write an extension method like this:
public static bool ToBoolean(this MyEnum value) {
return value == MyEnum.MyTrue;
}
and forget about it
Try this:
public enum MyEnum
{
MyFalse = 0,
MyTrue = 1
}
then:
MyEnum val = MyEnum.MyTrue;
bool IsThisTrue = val;
bool IsThisTrue = Convert.ToBoolean((int)val);
Given an enum type:
enum SOMEENUM
{
A = true,
B = false,
C = true
}
I want to switch on this like:
public void SWITCHON (SOMEENUM sn)
{
switch(s)
{
case SOMEENMUM.A : xxxxxxxx.......
}
}
But this doesn't compile; I guess it's using the bool value of the enum.
I want to do switch on Enum as if there is no value assigned to it.
First of all:
Enums in C# do not support bool as value.
So It should be integers.
If we set 2 property's of enum to the same value we can consider one of them lost.
From my understanding what you actually is trying to do is:
Somehow flag that 2 property's of enum are equal.
My suggestion:
public enum MyEnum
{
[Description("true")]
A = 1,
[Description("false")]
B = 2,
[Description("true")]
C = 3
}
Extension for Enum which will return bool
public static class EnumEx
{
public static bool GetDescriptionAsBool(this Enum value)
{
FieldInfo field = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute
= Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))
as DescriptionAttribute;
if(attribute == null)
{
//throw new SomethingWentWrongException();
}
return bool.Parse(attribute.Description);
}
}
As a result you can switch normally and at any time can check what is your enums boll flag just calling GetDescriptionAsBool method of that instance.
Repeated values are just different names for the same thing. There's no way to tell the difference because enums are stored as the values, not as the names.
As for bool values, you use an if for those instead of a switch.
enums require numerical values but do not have to be set. I suggest just removing leaving it like
enum SOMEENUM
{
A,
B,
C
}
so
public void SWITCHON (SOMEENUM s)
{
switch(s)
{
case SOMEENMUM.A : ...do stuff...
break;
case SOMEENMUM.B : ...do stuff...
break;
case SOMEENMUM.c : ...do stuff...
break;
}
}