I have a property LegalCaseStatus. My intention is to make the property to accept a predefined range of approved values. The range must be visible and unchanged throughtout my program. Here's an example of the list:
Plaintiff
Defendant
Third Party
Debitor
Creditor
Petitioner
So, the best way I could think of is to declare a static class, and fill it with corresponding constants:
public static class Participants
{
public const byte
Piaintiff = 0,
Defendant = 1,
ThirdParty = 2,
Debitor= 3,
Creditor = 4,
Petitioner = 5;
}
so after using a namespace I could just do:
public byte LegalCaseStasus = Plaintiff;
the only problem is, since it's just a byte member it'll accept anything that is byte:
LegalCaseStatus = 99; // ok
LegalCaseStatus = SomeOtherByteConstant; // ok
How do I protect the member LegalCaseStatus? Is my solution generally correct?
You can use enums - An enum is a special "class" that represents a group of constants (unchangeable/read-only variables). Sounds like the thing you describe in your question:
public enum Participants
{
Piaintiff = 0,
Defendant = 1,
ThirdParty = 2,
Debitor = 3,
Creditor = 4,
Petitioner = 5
}
After the enum definition you can use it exactly the way you want to:
Participants LegalCaseStasus = Participants.ThirdParty;
LegalCaseStasus = 99; // ERROR
byte underlying_value = (byte)LegalCaseStasus; // value == 2
Note: The underlying value of an enum is int! When you cast to byte you need to make sure there are no predefined values that exceed the byte limit.
Related
I am writing an application to record some hardware information of computers in our environment and I am unclear on an enum mapping from the Win32/CIM/WMI(?) API. I am getting VideoOutputTechnology from the root/wmi/wmimonitorconnectionparams class using the Microsoft.Management.Infrastructure library. This value is UInt32 enum - the source is visible here.
I have successfully mapped most of this to a C# enum, but I am unclear on how I would write out the last five values (see below). Is it true that D3DKMDT_VOT_SVIDEO_4PIN = D3DKMDT_VOT_SVIDEO = 1?
D3DKMDT_VOT_SVIDEO = 1,
D3DKMDT_VOT_COMPOSITE_VIDEO = 2,
D3DKMDT_VOT_COMPONENT_VIDEO = 3,
// omitted for brevity
D3DKMDT_VOT_SVIDEO_4PIN = D3DKMDT_VOT_SVIDEO,
D3DKMDT_VOT_SVIDEO_7PIN = D3DKMDT_VOT_SVIDEO,
D3DKMDT_VOT_RF = D3DKMDT_VOT_COMPOSITE_VIDEO,
D3DKMDT_VOT_RCA_3COMPONENT = D3DKMDT_VOT_COMPONENT_VIDEO,
D3DKMDT_VOT_BNC = D3DKMDT_VOT_COMPONENT_VIDEO,
My version of this code looks similar to the following:
public enum WmiMonitorConnectionParamsVideoOutputTechnology : uint
{
SVideo = 1,
CompositeVideo = 2,
ComponentVideo = 3,
// Is this correct?
SVideo4Pin = WmiMonitorConnectionParamsVideoOutputTechnology.SVideo,
SVideo7Pin = WmiMonitorConnectionParamsVideoOutputTechnology.SVideo,
RF = WmiMonitorConnectionParamsVideoOutputTechnology.CompositeVideo,
RCA_3COMPONENT = WmiMonitorConnectionParamsVideoOutputTechnology.ComponentVideo,
BNC = WmiMonitorConnectionParamsVideoOutputTechnology.ComponentVideo,
}
I realize that this appears to be an Int32 type in this source code, but it's coming from CIM as UInt32. However, that does not change my question on mapping these enum values
I found this information here.
Frankly, I'm not really sure what I'm looking at so I'm having trouble phrasing a question on Google to get the right answer.
Here is the declaration of the RotateFlipType enumeration from .NET 4:
public enum RotateFlipType
{
Rotate180FlipXY = 0,
RotateNoneFlipNone = 0,
Rotate270FlipXY = 1,
Rotate90FlipNone = 1,
Rotate180FlipNone = 2,
RotateNoneFlipXY = 2,
Rotate270FlipNone = 3,
Rotate90FlipXY = 3,
Rotate180FlipY = 4,
RotateNoneFlipX = 4,
Rotate90FlipX = 5,
Rotate270FlipY = 5,
RotateNoneFlipY = 6,
Rotate180FlipX = 6,
Rotate90FlipY = 7,
Rotate270FlipX = 7,
}
I understand how the values are paired together for operations that would otherwise have the same result. The above enumeration becomes unfriendly when comparing debugger values against RotateFlipType.ToString values. Also not good for data binding scenarios. For example:
var value = RotateFlipType.RotateNoneFlipNone; // Debugger shows correct string for [value] which is [RotateNoneFlipNone].
var text = value.ToString(); // Output of [text] is [Rotate180FlipXY]. Presumably because it is declared first in the list.
Does this have anything to do with ordering of operations? Could they have not used [Flags] or split the enumeration into two (separating Rotation and Flipping)?
I realize the horse is long gone, no need to close the barn door, but...
These constants were chosen in this pattern to make image reflections easier.
To flip horizontally, one can use this simple operation:
rotation_value ^= 4;
Vertical flip:
rotation_value ^= 6;
Flip both at the same time (180 degree rotation):
rotation_value ^= 2;
Enums override the ToString method to use Enum.GetName in order to find the name of the given value. And for GetName, MSDN has the following remark:
If multiple enumeration members have the same underlying value, the
GetName method guarantees that it will return the name of one of those
enumeration members. However, it does not guarantee that it will
always return the name of the same enumeration member. As a result,
when multiple enumeration members have the same value, your
application code should never depend on the method returning a
particular member's name.
So, if multiple members have the same value, there is no guarantee that ToString will give you the original name.
Please consider this code:
public enum Status
{
S1 = 1,
S2 = 2,
S3 = 3,
S4 = 4
}
I know I can pass multiple enum using | oerator to a method:
public void DoWork(Status S)
{
}
...
DoWork(Status.S1 | Status.S2);
Now In DoWork Method I want to get values of passed enums. For Example In above code I want to get {1, 2}. How I cas do this?
thanks
Here are few steps to follow to get flagged enum :
Use 2 exp (n) integer (1, 2, 4, 8, 16, 32, ...)
to define your enum. Why ? : Actually each active state of your
enum will take a single bit of a 32 bits integer.
Add the Flags attribute.
Then,
[Flags]
public enum Status
{
S1 = 1,
S2 = 2,
S3 = 4,
S4 = 8
}
You can use Enum.HasFlag to check if a specific status is active :
public void DoWork(Status s)
{
var statusResult = Enum.GetValues(typeof(Status)).Where(v => s.HasFlag(v)).ToArray() ;
// StatusResult should now contains {1, 2}
}
Declare your parameters with the params tag, then you get an array of enums:
public void DoWork (params Status[] args) {
Console.WriteLine(args.Length);
}
Then you just pass them in as regular parameters:
DoWork(Status.S1, Status.S2);
This doesn't require changes to your enums, and easily copes with additional values. The flags solution above may work for you as well - depends on your requirements.
If this is the Integer values of your enums that you want you can use this :
//declare your enum as byte
public enum Status : byte
{...}
**EDITED**
//then cast it to int to use the value
DoWork((int)Status.S1 , (int)Status.S2);
//change doWork to accept int[]
public void DoWork (params int[] args)
In C, enums, internally equates to an integer. Therefore we can treat data types of enum as integer also.
How to achieve the same with C#?
Firstly, there could be two values that you're referring to:
Underlying Value
If you are asking about the underlying value, which could be any of these types: byte, sbyte, short, ushort, int, uint, long or ulong
Then you can simply cast it to it's underlying type. Assuming it's an int, you can do it like this:
int eValue = (int)enumValue;
However, also be aware of each items default value (first item is 0, second is 1 and so on) and the fact that each item could have been assigned a new value, which may not necessarily be in any order particular order! (Credit to #JohnStock for the poke to clarify).
This example assigns each a new value, and show the value returned:
public enum MyEnum
{
MyValue1 = 34,
MyValue2 = 27
}
(int)MyEnum.MyValue2 == 27; // True
Index Value
The above is generally the most commonly required value, and is what your question detail suggests you need, however each value also has an index value (which you refer to in the title). If you require this then please see other answers below for details.
Another way to convert an Enum-Type to an int:
enum E
{
A = 1, /* index 0 */
B = 2, /* index 1 */
C = 4, /* index 2 */
D = 4 /* index 3, duplicate use of 4 */
}
void Main()
{
E e = E.C;
int index = Array.IndexOf(Enum.GetValues(e.GetType()), e);
// index is 2
E f = (E)(Enum.GetValues(e.GetType())).GetValue(index);
// f is E.C
}
More complex but independent from the INT values assigned to the enum values.
By default the underlying type of each element in the enum is integer.
enum Values
{
A,
B,
C
}
You can also specify custom value for each item:
enum Values
{
A = 10,
B = 11,
C = 12
}
int x = (int)Values.A; // x will be 10;
Note: By default, the first enumerator has the value 0.
You can directly cast it:
enum MyMonthEnum { January = 1, February, March, April, May, June, July, August, September, October, November, December };
public static string GetMyMonthName(int MonthIndex)
{
MyMonthEnum MonthName = (MyMonthEnum)MonthIndex;
return MonthName.ToString();
}
For Example:
string MySelectedMonthName=GetMyMonthName(8);
//then MySelectedMonthName value will be August.
Use simple casting:
int value = (int) enum.item;
Refer to enum (C# Reference)
Use a cast:
public enum MyEnum : int {
A = 0,
B = 1,
AB = 2,
}
int val = (int)MyEnum.A;
using System;
public class EnumTest
{
enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};
static void Main()
{
int x = (int)Days.Sun;
int y = (int)Days.Fri;
Console.WriteLine("Sun = {0}", x);
Console.WriteLine("Fri = {0}", y);
}
}
One reason that the designers c# might have chosen to NOT have enums auto convert was to prevent accidentally mixing different enum types...
e.g. this is bad code followed by a good version
enum ParkingLevel { GroundLevel, FirstFloor};
enum ParkingFacing { North, East, South, West }
void Test()
{
var parking = ParkingFacing.North; // NOT A LEVEL
// WHOOPS at least warning in editor/compile on calls
WhichLevel(parking);
// BAD wrong type of index, no warning
var info = ParkinglevelArray[ (int)parking ];
}
// however you can write this, looks complicated
// but avoids using casts every time AND stops miss-use
void Test()
{
ParkingLevelManager levels = new ParkingLevelManager();
// assign info to each level
var parking = ParkingFacing.North;
// Next line wrong mixing type
// but great you get warning in editor or at compile time
var info=levels[parking];
// and.... no cast needed for correct use
var pl = ParkingLevel.GroundLevel;
var infoCorrect=levels[pl];
}
class ParkingLevelInfo { /*...*/ }
class ParkingLevelManager
{
List<ParkingLevelInfo> m_list;
public ParkingLevelInfo this[ParkingLevel x]
{ get{ return m_list[(int)x]; } }}
In answering this question I define 'value' as the value of the enum item, and index as is positional location in the Enum definition (which is sorted by value). The OP's question asks for 'index' and various answer have interpreted this as either 'index' or 'value' (by my definitions). Sometimes the index is equal to numerical value.
No answer has specifically addressed the case of finding the index (not value) where the Enum is an Enum flag.
Enum Flag
{
none = 0 // not a flag, thus index =-1
A = 1 << 0, // index should be 0
B = 1 << 1, // index should be 1
C = 1 << 2, // index should be 2
D = 1 << 3, // index should be 3,
AandB = A | B // index is composite, thus index = -1 indicating undefined
All = -1 //index is composite, thus index = -1 indicating undefined
}
In the case of Flag Enums, the index is simply given by
var index = (int)(Math.Log2((int)flag)); //Shows the maths, but is inefficient
However, the above solution is
(a) Inefficient as pointed out by #phuclv (Math.Log2() is floating point and costly) and
(b) Does not address the Flag.none case, nor any composite flags - flags that are composed of other flags (eg the 'AandB' flag as in my example).
DotNetCore
If using dot net core we can address both a) and b) above as follows:
int setbits = BitOperations.PopCount((uint)flag); //get number of set bits
if (setbits != 1) //Finds ECalFlags.none, and all composite flags
return -1; //undefined index
int index = BitOperations.TrailingZeroCount((uint)flag); //Efficient bit operation
Not DotNetCore
The BitOperations only work in dot net core. See #phuclv answer here for some efficient suggestions https://stackoverflow.com/a/63582586/6630192
#user1027167 answer will not work if composite flags are used, as per my comment on his answer
Thankyou to #phuclv for suggestions on improving efficiency
Hi before going to direct problem let me show my code :
//Definition of enum
public enum LogType
{
Warning = -2,
Error = -1,
Info = 0,
EruCtorDtor = 1,
Notifications = 2,
CommunicationWithAOT = 4,
ExecutedOrder = 8,
ERUInfo = 16,
DebugLog = 32,
}
//Use of enum
CurrentLogFlagSettings = nLogFlag;
LogFlagMap = new SortedDictionary<LogType, int>();
ulong mask = 1;
while(mask <= nLogFlag)
{
if ((nLogFlag & mask) == mask)
{
LogType type = (LogType)mask; //Step 1
string val = type.ToString(); //Step 2
//Processing the value
LogFlagMap.Add(type, tempVal)
LogMsg(val + " added", type);
}
mask <<= 1;
}
What I want is : Process step2 only after step1 has produced valid value. I mean value should be between range defined in enum definition. Otherwise I dont want to process it.
for e.g.
case 1 - Lets say mask value is 32,
its defined in enum. So type is
getting value DebugLog and so it
type.ToString() (i.e. "DebugLog"),
this is a valid case.
case 2- Lets
say mask value is 128 and its not
defined in enum, in this case I dont
want to process anything on 128
value. But what is happening its
geting value 128 in type and
type.ToString() is converting it
into 128. I dont want this, I want
to make sure whether 128 belongs to
enum values or not.
I want to prevent 2nd case to be executed. Is there any solution for my problem?
Please let me know if more details are needed.
You could use Enum.IsDefined, like so:
int value = 128;
Console.WriteLine(Enum.IsDefined(typeof(LogType), value)); // will print out False
Firstly, let me seriously apologise, Ive had like no sleep, so if I missed the point a little. Please, just ignore me.
You can enumerate your LogType with Enum.GetValues(typeof(LogType))), so you could step through and check a value against it. I had some code, but, I couldnt promise it compiled.
Bool isValid(int i)
{
foreach (LogType l in Enum.GetValues(typeof(LogType)))
{
if ((int)l == i) return true;
}
return false;
}
You can also use Enum.GetValues(typeof(LogType)) to get all the possible values for your enum and do what you want through that.
i.e.
var values = Enum.GetValues(typeof (LogType));
foreach (LogType type in values)
{
if (((int)type & nLogMask) == (int)type)
{
//value is valid, process the value
}
}
One addition to your code could be the addition of the [Flags] attribute to you enum, this then makes it clear that the enum values are for bitwise operations
e.g.
[Flags]
public enum LogType
{
Warning = -2,
Error = -1,
Info = 0,
EruCtorDtor = 1,
Notifications = 2,
CommunicationWithAOT = 4,
ExecutedOrder = 8,
ERUInfo = 16,
DebugLog = 32,
}
although to do this, you would need to change the values such that the Warning and Error take the top 2 bits of the enum value (assuming this is still necessary).
The c# Enum class also has the method GetName(). This might provide a nice and easy manner to retrieve the name of the value set
e.g.
Enum.GetName( typeof(LogType), 4 ); // result = CommunicationWithAOT
I have a library called Unconstrained Melody which allows you to express all of this in a type-safe generic way and avoids boxing too. Personally I prefer that over using Enum.IsDefined, but obviously that doesn't involve learning an extra library.
It's probably not worth using Unconstrained Melody if this is the only thing you need to do with your enum, but if you've got other similar operations, you may wish to consider it.