Is there a way to add an "All values" option to an enum without having to change its value every time a new value is added to the enum?
[Flags]
public enum SomeEnum
{
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
All = ?
}
Update:
Ended up inheriting from long and using long.MaxValue for All option.
Since you should define the empty value in a Flags enum such as None = 0, the simplest way of defining the Allvalue is by simply inverting all the bits inNone`.
[Flags]
enum MyEnum
{
None = 0,
A = 1,
B = 2,
C = 4,
...
All = ~None
}
Note that ~0 instead of ~None will not work for unsigned backing types as that is -1, which is not a valid value for unsigned.
Edit: Answer was modified to use an inverted None instead of an explicit constant such as 0x7FFFFFFF or ~0, as this also works for unsigned
It should be like this:
[Flags]
public enum SomeEnum
{
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
All = SomeValue | SomeValue2 | SomeValue3 | SomeValue4
}
An enum can be made of many different length integer types (short, int, long). This makes the #FFFFFFFF solution inappropriate (as pointed out in #MarcGravell comment).
An enum can be made of unsigned types (uint for isntance). This makes the -1 solution inappropriate.
My best bet is, maintenance-free:
All = ~0
The Idea is to use the behavior of the enum to calculate the last value.
Add Last field after all 'real' enum values.
Add All field equals to (Last << 1) - 3.
[Flags]
public enum SomeEnum
{
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
// Do not add values after this
Last,
All = (Last << 1) - 3,
}
I answered it at: How to use Enum with aditional options (All, None)
You can check my blog at Enum Trick for more information and ideas.
No, there is nothing built is that will make such an All option automatically update when the Enum changes.
You may want to have a special value (monitor value) that means All (say -1), even if it is not the bitwise sum of all of the options.
An alternative is to use a value that has all of the bits switched on:
All = 0xFFFFFFFF
You can use a little trick
(SomeEnum)( (1 << ( Enum.GetValues( typeof(SomeEnum) ).Length ) ) -1 )
If you added a 'None' Enum name with value = 0 ( None = 0, ) then you need to put a '-1' after the Length.
This is possible if you're okay with a static readonly field in a separate type, rather than as a const enum field:
[Flags]
public enum SomeEnum
{
None = 0,
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
}
public static class SomeEnumUtility {
private static readonly SomeEnum[] _someEnumValues = (SomeEnum[])Enum.GetValues( typeof(SomeEnum) );
public static readonly SomeEnum SomeEnum_All = GetSomeEnumAll();
// Unfortunately C# does not support "enum generics" otherwise this could be a generic method for any Enum type
private static SomeEnum GetSomeEnumAll() {
SomeEnum value = SomeEnum.None; // or `(SomeEnum)0;` if None is undefined.
foreach(SomeEnum option in _someEnumValues) {
value |= option;
}
return value;
}
}
Then you can get SomeEnumUtility.SomeEnum_All. As it's a static readonly the computation is only performed once, in a thread-safe manner.
As I wrote in the code-comment, it's unfortunate that C# does not support enum generics, otherwise you could do this:
private static TEnum GetEnumAllFlags<TEnum>() where TEnum : enum {
TEnum[] allValues = Enum.GetValues<TEnum>();
TEnum value = (TEnum)0;
foreach(TEnum option in allValues) {
value |= option;
}
return value;
}
Oh well :(
public static T EnumSetAll<T>() where T : struct, Enum
{
string str = string.Join(", ", Enum.GetNames(typeof(T)));
if (Enum.TryParse<T>(str, out var e))
return e;
return default;
}
Related
I have an enumeration like so:
[Flags]
public enum UserProcessStage : uint
{
ShopSelection = 1,
FillBasket = 2,
SpecifyShipmentCredentials = 4,
SpecifyPaymentCredentials = 8,
OrderComplete = 16
}
Assuming I have a variable whose value is FillBakset (2), what I want to do is be able to increment it to the next value that is defined within the enumeration (SpecifyShipmentCredentials, 4).
The problem is that incrementing it causes its value to be 3 since it is based on an integer, I tried multipliying it by 2 but got a compilation error.
How could I increment an enumeration value to the next one ?
Thanks
You can use this code. It basically orders the enum by underlying value and then givs you the first enum which is bigger than the one specified. If none found, it will return 0 because of DefaultIfEmty():
public static UserProcessStage GetNext(UserProcessStage value)
{
return (from UserProcessStage val in Enum.GetValues(typeof (UserProcessStage))
where val > value
orderby val
select val).DefaultIfEmpty().First();
}
I am trying to figure out the difference between these two enums
public enum EnumA
{
A = 1,
B = 2,
C = 3
}
vs
public enum EnumB : byte
{
A = 1,
B = 2,
C = 3
}
I know that the default base type of enum is int, so If I change base type to byte how its going to impact?
You will only be able to use value 0-255 for the enum. This is probably plenty, if you're not using the enum as flags, then you are limited to only 8 different flags.
Given the following enum:
[Flags]
public enum Intervals
{
Root = PerfectUnison,
Unison = PerfectUnison,
PerfectUnison = 1 << 0,
AugmentedUnison = MinorSecond,
MinorSecond = 1 << 1,
Second = MajorSecond,
MajorSecond = 1 << 2,
AugmentedSecond = MinorThird,
MinorThird = 1 << 3,
Third = MajorThird,
MajorThird = 1 << 4,
AugmentedThird = PerfectFourth,
DoubleAugmentedThird = Triton,
DiminishedFourth = MajorThird,
Fourth = PerfectFourth,
PerfectFourth = 1 << 5,
AugmentedFourth = Triton,
DoubleAugmentedFourth = PerfectFifth,
Triton = 1 << 6,
//...Removed for brevity, see link to code bellow
}
I'm trying this simple test:
static void Main(string[] args)
{
var values = Enum.GetValues(typeof(Intervals));
foreach (var value in values)
{
Console.WriteLine(value);
}
}
And here is the output:
PerfectUnison, PerfectUnison, PerfectUnison, AugmentedUnison, AugmentedUnison, Second, Second, MinorThird, MinorThird, DiminishedFourth, DiminishedFourth, DiminishedFourth, AugmentedThird, AugmentedThird, AugmentedThird, AugmentedThird, DoubleDiminishedSixth, DoubleDiminishedSixth etc.
While I want the enum names selected for identical values to be of the following sequence:
Root, MinorSecond, Second, MinorThird, Third, Fourth, Triton, Fifth, MinorSixth, Sixth, MinorSeventh, Seventh, Octave, MinorNinth, Ninth, Tenth, Eleventh, MajorEleventh, Thirteen
A good reproduction would also be Enum.GetNames. I want the names of the above group should always precede their value-matching names.
I'm basically looking for a documentation of the rules of precedence/priority of enum names per value.
You can play around with the code here: http://rextester.com/EJOWK87857.
Update
I'm now looking into decompiled Enum.GetNames. Looks like it uses reflection. So the question is then, "How to control the order of reflected fields?".
Without using metadata, this is not possible since the compiler may assign the constant value to each enum member. Examining the compiled IL shows that the assignment information is lost when the code is compiled:
.field public static literal valuetype .../Intervals Unison = int32(1)
.field public static literal valuetype .../Intervals PerfectUnison = int32(1)
.field public static literal valuetype .../Intervals AugmentedUnison = int32(2)
...
Since this information is lost when the source is compiled (or, at least, is not guaranteed to be available), it would not be possible to assign priority rules based on assignment at runtime. This limitation is consistent with the documentation for Enum.ToString(), which states that if multiple names are associated with the same value, the member chosen is nondeterministic:
If multiple enumeration members have the same underlying value and you attempt to retrieve the string representation of an enumeration member's name based on its underlying value, your code should not make any assumptions about which name the method will return.
This said, a possible workaround may be to assign attribute values to the enum values that are deemed to be a priority on assignment. For instance:
[AttributeUsage(AttributeTargets.Field)]
class PriorityAttribute : Attribute { }
[Flags]
public enum Intervals
{
Root = PerfectUnison,
Unison = PerfectUnison,
[Priority]
PerfectUnison = 1 << 0,
AugmentedUnison = MinorSecond,
[Priority]
MinorSecond = 1 << 1,
Second = MajorSecond,
[Priority]
MajorSecond = 1 << 2,
AugmentedSecond = MinorThird,
...
Since the attribute information is associated with the enum values at runtime, the marked enumeration names can be accessed at runtime:
typeof(Intervals)
.GetFields()
.Where(a => a.GetCustomAttributes(typeof(PriorityAttribute), false).Length > 0)
.Select(a => a.Name))
Likewise, you can write an analogue to Enum.GetName to return only the names with the attribute defined (e.g., GetPriorityName(typeof(Intervals), 1) will always return PerfectUnison.
static string GetPriorityName(Type enumType, object v)
{
Type ut = Enum.GetUnderlyingType(enumType);
var pty = enumType.GetFields()
.Where(
a => a.IsLiteral
&& a.GetRawConstantValue().Equals(v)
&& a.GetCustomAttributes(typeof(PriorityAttribute), false).Length > 0
)
.FirstOrDefault();
if (pty == null)
return Enum.GetName(enumType, v); // default to standard if no priority defined
return pty.Name;
}
I stumbled upon the usage of the plus (+) operator in an enum definition today, I was surprised to see the accompanying tests pass. Anyone have any idea where this may be documented?
public enum ApprovalItemState
{
Enqueued = 1,
Approved = 2,
Denied = 4,
Acknowledged = 8,
ApprovalAcknowledged = ApprovalItemState.Approved + ApprovalItemState.Acknowledged,
DenialAcknowledged = ApprovalItemState.Denied + ApprovalItemState.Acknowledged
}
[TestClass]
public class ApprovalItemStateTests
{
[TestMethod]
public void AreFlagsDeniedAndAcknowledged()
{
Assert.AreEqual(ApprovalItemState.DenialAcknowledged, ApprovalItemState.Denied | ApprovalItemState.Acknowledged);
}
[TestMethod]
public void IsDenialAcknowledged()
{
Assert.IsTrue(Enum.IsDefined(typeof(ApprovalItemState), ApprovalItemState.Denied | ApprovalItemState.Acknowledged));
Assert.AreEqual(ApprovalItemState.Denied | ApprovalItemState.Acknowledged, (ApprovalItemState)Enum.Parse(typeof(ApprovalItemState), "DenialAcknowledged"));
}
[TestMethod]
public void IsNotDeniedAndApproved()
{
Assert.IsFalse(Enum.IsDefined(typeof(ApprovalItemState), ApprovalItemState.Approved | ApprovalItemState.Denied));
}
}
Reed's answer is of course correct. I just thought I'd add an interesting bit of trivia. First off, when you are inside the enum, all the members of the enum are in scope. This is the only situation in C# in which you can use an enum member via its unqualified name!
public enum ApprovalItemState
{
Enqueued = 1,
Approved = 2,
Denied = 4,
Acknowledged = 8,
ApprovalAcknowledged = Approved | Acknowledged,
DenialAcknowledged = Denied | Acknowledged
}
The second trivia point is that the C# compiler actually allows enum arithmetic involving other enums inside an enum!
enum E
{
E1
}
enum F
{
F1
}
enum G
{
G1 = E.E1 + F.F1
}
Normally that would not be at all legal; you cannot add two dissimilar enums together and you cannot assign the result. The compiler relaxes those rules inside an enum initializer so that you can do things like:
enum MyFlags
{
MyReadOnly = FileFlags.ReadOnly,
...
The C# Language Spec, in 14.5, states:
The following operators can be used on values of enum types: ==, !=, <, >, <=, >= (§7.10.5), binary + (§7.8.4), binary ‑ (§7.8.5), ^, &, | (§7.11.2), ~ (§7.7.4), ++ and -- (§7.6.9 and §7.7.5).
Basically, since the enum is internally stored as an Int32 (that's the default, unless you specify a different storage type), you can use addition like this.
However, it's far more common to use | instead of + to define masks. Also, it would be common to include [Flags] if you're going to use this as a flags enumeration.
From the C# reference on enum:
...Every enumeration type has an underlying type, which can be any integral type except char. The default underlying type of the enumeration elements is int...
By the way, it is more idiomatic (and less error prone) to use | instead of + to combine enum flag values. For example, this mistake won't cause a problem:
DenialAcknowledged =
ApprovalItemState.Denied
| ApprovalItemState.Acknowledged
| ApprovalItemState.Denied
But this mistake will cause a problem:
DenialAcknowledged =
ApprovalItemState.Denied
+ ApprovalItemState.Acknowledged
+ ApprovalItemState.Denied
Approved + Acknowledged is just a constant so it can be assigned as a value to enum element.
Regarding tests -- they work because int values are "happy ones", so (a + b) == (a | b)
However if your change that to something like that:
public enum ApprovalItemState
{
Enqueued = 1,
Approved = 2,
Denied = 7,
Acknowledged = 18,
ApprovalAcknowledged = Approved + Acknowledged,
DenialAcknowledged = Denied + Acknowledged
}
and tests won't pass.
It's not surprising - enums are represented by integral types. You can use other operators as well, although if you're going to use flags (which this example is doing), it's far better to use the [Flags] attribute to define them and better to lay out the bits more clearly:
[Flags]
public enum ApprovalItemState
{
Enqueued = 1 << 0,
Approved = 1 << 1,
Denied = 1 << 2,
Acknowledged = 1 << 3,
ApprovalAcknowledged = ApprovalItemState.Approved | ApprovalItemState.Acknowledged,
DenialAcknowledged = ApprovalItemState.Denied | ApprovalItemState.Acknowledged
}
I'll break down one of these for you.
DenialAcknowledged = ApprovalItemState.Denied + ApprovalItemState.Acknowledged
DenialAcknowledged = 4 + 8
DenialAcknowledged = 12
For this test:
[TestMethod]
public void AreFlagsDeniedAndAcknowledged()
{
Assert.AreEqual(ApprovalItemState.DenialAcknowledged, ApprovalItemState.Denied | ApprovalItemState.Acknowledged);
}
You're checking:
ApprovalItemState.DenialAcknowledged == ApprovalItemState.Denied | ApprovalItemState.Acknowledged
12 == 4 | 8
12 == 0100 | 1000 //bitwise operation
12 == 1100
12 == 12 //convert from binary to decimal
And that is why the test pass. Not exactly straightforward by looking at the code.
How do you get the max value of an enum?
Enum.GetValues() seems to return the values in order, so you can do something like this:
// given this enum:
public enum Foo
{
Fizz = 3,
Bar = 1,
Bang = 2
}
// this gets Fizz
var lastFoo = Enum.GetValues(typeof(Foo)).Cast<Foo>().Last();
Edit
For those not willing to read through the comments: You can also do it this way:
var lastFoo = Enum.GetValues(typeof(Foo)).Cast<Foo>().Max();
... which will work when some of your enum values are negative.
I agree with Matt's answer. If you need just min and max int values, then you can do it as follows.
Maximum:
Enum.GetValues(typeof(Foo)).Cast<int>().Max();
Minimum:
Enum.GetValues(typeof(Foo)).Cast<int>().Min();
According to Matt Hamilton's answer, I thought on creating an Extension method for it.
Since ValueType is not accepted as a generic type parameter constraint, I didn't find a better way to restrict T to Enum but the following.
Any ideas would be really appreciated.
PS. please ignore my VB implicitness, I love using VB in this way, that's the strength of VB and that's why I love VB.
Howeva, here it is:
C#:
static void Main(string[] args)
{
MyEnum x = GetMaxValue<MyEnum>(); //In newer versions of C# (7.3+)
MyEnum y = GetMaxValueOld<MyEnum>();
}
public static TEnum GetMaxValue<TEnum>()
where TEnum : Enum
{
return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Max();
}
//When C# version is smaller than 7.3, use this:
public static TEnum GetMaxValueOld<TEnum>()
where TEnum : IComparable, IConvertible, IFormattable
{
Type type = typeof(TEnum);
if (!type.IsSubclassOf(typeof(Enum)))
throw new
InvalidCastException
("Cannot cast '" + type.FullName + "' to System.Enum.");
return (TEnum)Enum.ToObject(type, Enum.GetValues(type).Cast<int>().Last());
}
enum MyEnum
{
ValueOne,
ValueTwo
}
VB:
Public Function GetMaxValue _
(Of TEnum As {IComparable, IConvertible, IFormattable})() As TEnum
Dim type = GetType(TEnum)
If Not type.IsSubclassOf(GetType([Enum])) Then _
Throw New InvalidCastException _
("Cannot cast '" & type.FullName & "' to System.Enum.")
Return [Enum].ToObject(type, [Enum].GetValues(type) _
.Cast(Of Integer).Last)
End Function
This is slightly nitpicky but the actual maximum value of any enum is Int32.MaxValue (assuming it's a enum derived from int). It's perfectly legal to cast any Int32 value to an any enum regardless of whether or not it actually declared a member with that value.
Legal:
enum SomeEnum
{
Fizz = 42
}
public static void SomeFunc()
{
SomeEnum e = (SomeEnum)5;
}
After tried another time, I got this extension method:
public static class EnumExtension
{
public static int Max(this Enum enumType)
{
return Enum.GetValues(enumType.GetType()).Cast<int>().Max();
}
}
class Program
{
enum enum1 { one, two, second, third };
enum enum2 { s1 = 10, s2 = 8, s3, s4 };
enum enum3 { f1 = -1, f2 = 3, f3 = -3, f4 };
static void Main(string[] args)
{
Console.WriteLine(enum1.one.Max());
}
}
Use the Last function could not get the max value. Use the "max" function could. Like:
class Program
{
enum enum1 { one, two, second, third };
enum enum2 { s1 = 10, s2 = 8, s3, s4 };
enum enum3 { f1 = -1, f2 = 3, f3 = -3, f4 };
static void Main(string[] args)
{
TestMaxEnumValue(typeof(enum1));
TestMaxEnumValue(typeof(enum2));
TestMaxEnumValue(typeof(enum3));
}
static void TestMaxEnumValue(Type enumType)
{
Enum.GetValues(enumType).Cast<Int32>().ToList().ForEach(item =>
Console.WriteLine(item.ToString()));
int maxValue = Enum.GetValues(enumType).Cast<int>().Max();
Console.WriteLine("The max value of {0} is {1}", enumType.Name, maxValue);
}
}
In agreement with Matthew J Sullivan, for C#:
Enum.GetValues(typeof(MyEnum)).GetUpperBound(0);
I'm really not sure why anyone would want to use:
Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Last();
...As word-for-word, semantically speaking, it doesn't seem to make as much sense? (always good to have different ways, but I don't see the benefit in the latter.)
There are methods for getting information about enumerated types under System.Enum.
So, in a VB.Net project in Visual Studio I can type "System.Enum." and the intellisense brings up all sorts of goodness.
One method in particular is System.Enum.GetValues(), which returns an array of the enumerated values. Once you've got the array, you should be able to do whatever is appropriate for your particular circumstances.
In my case, my enumerated values started at zero and skipped no numbers, so to get the max value for my enum I just need to know how many elements were in the array.
VB.Net code snippets:
'''''''
Enum MattType
zerothValue = 0
firstValue = 1
secondValue = 2
thirdValue = 3
End Enum
'''''''
Dim iMax As Integer
iMax = System.Enum.GetValues(GetType(MattType)).GetUpperBound(0)
MessageBox.Show(iMax.ToString, "Max MattType Enum Value")
'''''''
I used the following when I needed the min and max values of my enum.
I just set a min equal to the lowest value of the enumeration and a max equal to the highest value in the enumeration as enum values themselves.
public enum ChannelMessageTypes : byte
{
Min = 0x80, // Or could be: Min = NoteOff
NoteOff = 0x80,
NoteOn = 0x90,
PolyKeyPressure = 0xA0,
ControlChange = 0xB0,
ProgramChange = 0xC0,
ChannelAfterTouch = 0xD0,
PitchBend = 0xE0,
Max = 0xE0 // Or could be: Max = PitchBend
}
// I use it like this to check if a ... is a channel message.
if(... >= ChannelMessageTypes.Min || ... <= ChannelMessages.Max)
{
Console.WriteLine("Channel message received!");
}
In F#, with a helper function to convert the enum to a sequence:
type Foo =
| Fizz = 3
| Bang = 2
// Helper function to convert enum to a sequence. This is also useful for iterating.
// stackoverflow.com/questions/972307/can-you-loop-through-all-enum-values-c
let ToSeq (a : 'A when 'A : enum<'B>) =
Enum.GetValues(typeof<'A>).Cast<'B>()
// Get the max of Foo
let FooMax = ToSeq (Foo()) |> Seq.max
Running it...
> type Foo = | Fizz = 3 | Bang = 2
> val ToSeq : 'A -> seq<'B> when 'A : enum<'B>
> val FooMax : Foo = Fizz
The when 'A : enum<'B> is not required by the compiler for the definition, but is required for any use of ToSeq, even by a valid enum type.
It is not usable in all circumstances, but I often define the max value myself:
enum Values {
one,
two,
tree,
End,
}
for (Values i = 0; i < Values.End; i++) {
Console.WriteLine(i);
}
var random = new Random();
Console.WriteLine(random.Next((int)Values.End));
Of course this won't work when you use custom values in an enum, but often it can be an easy solution.