Can I assign an enum based on an array of strings? - c#

I have a struct for a game I am building that looks like this:
using System;
public readonly struct Target
{
public Target((int Min, int Max) range, string[] targetTypes)
{
Range = range;
TargetType = ParseTypes(targetTypes);
}
public (int Min, int Max) Range { get; }
public TargetTypes TargetType { get; }
[Flags]
public enum TargetTypes { None = 0, Self = 1, Enemy = 2, Player = 4, Character = 8, Area = 16 }
}
I would like to take all of the values in the string array and cast them into a single enum (not an array of enum values, which I believe is what is happening in the answer to this question).
The thing is a Target can have multiple types. I figured an enum was the best way to represent this, and also figured defining the enum inside the struct wasn't a terrible idea, but this could be an anti-pattern (coming from a JS background, be gentle!).
I like this whole enumeration types as bit flags thing, hence the numbering, that's what sent me down this path.
Yes, I control the inputs, so happy to hear why/how I should do this differently - thanks for your time!

You could use the following.
TargetType = (TargetTypes)Enum.Parse(typeof(TargetTypes),string.Join(",",targetTypes));
The second parameter of Enum.Parse accepts either a single value/constant representing the enum or a list of named constants or underlying values delimited by commas (,).

Thank you #asawyer for pointing the way. I missed an important part of the documentation (always RFTM twice!):
Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
There's no need for anything fancy here, Parse does the trick:
TargetType = (TargetTypes) Enum.Parse(typeof(TargetTypes), string.Join(",", targetTypes));

Related

Is there a type that is the opposite of an enum?

For example, here is a simple enum:
enum Something {
One = 1,
Two = 2,
Three = 3
}
But I would like to create the opposite of this code, like
SomeType Something {
1 = One,
2 = Two,
3 = Threee
}
Maybe I could introduce constants, like
static class Something {
public const 1 = "One";
// ...
}
but I get compiler errors (CS1031, CS1001, CS0145 and CS1003), because c# can't handle this.
I can do the same with enums to prevent these unnecessary errors, but here I also get CS1001, because c# does not undertand that the numbers are the identifiers.
I can also use strings, but this makes it even more complicated, because c# expects another identifier for them (but doesn't accept one (CS0029))
So, is there anything in c# that can be used to assign some string-like values to numbers as constants or like enums?
You can not have numeric value as your variable name, So to solve this issue you can create a Dictionary of key integer and value as string like this Dictionary<int, string> and use it accordingly.
If that's how to use the enum name, you can use Enum.TryParse<someEnumTyme>(someString, out _someEnumVar).
But the Dictionary solution of is more elegant in my opinion.
At runtime, for many operations, using an enum variable is the same as using the underlying type.
enum Something {
One = 1,
Two = 2,
Three = 3
}
Something foo = Something.One; // assign 1 to foo
You can use the definition of an enum to create a mapping between values and names;
var lookup = ((Something[])Enum.GetValues(typeof(Something)))
.ToDictionary(e => e.ToString(), e => (int)e);

Indexing a BitArray where bits are defined by a generic Enum

I'm working with pulling a stream of bytes off of a medical device, and have run into a really annoying data structure. Basically, I am getting back a 2-byte chunk where each bit represents a boolean value. This structure appears frequently enough in the byte stream to develop a struct/class around it, but in each instance, the bits mean completely different things.
So first I set up a bunch of Enums to represent all the different definitions the bit structure could have. (Note that not every bit is used in every definition. Sometimes there are breaks in between the important bits.)
EDIT: Removed all names that looked like 'flag.' I'm not using the [Flags] attribute, and this seems to be a point of contention/confusion. The enum values are simply mapped to the indices in my BitArray.
public enum RecordInfo { AM_TEST = 0, PM_TEST, TEST_VALIDITY };
public enum RecordAlerts { ALERT1 = 0, ALERT2, ALERT3, ALERT4, VALIDATED = 15 };
Then created this container to hold the actual bits:
public struct TwoBytes<TEnum> where TEnum : struct, IConvertible
{
private BitArray _bits = new BitArray(2);
}
This seems to work as I need, until I want to index my structure based on an Enum name. So say I have a TwoByte struct called Alerts, and this contains some bit values. If I want to get a specific flag like this:
bool alert3Set = Alerts[RecordAlerts.ALERT3]
I end up with a truly heinous index function. This is what I have in place now:
public bool this[TEnum name]
{
get
{
int index = Enum.GetValues(typeof(TEnum)).Cast<TEnum>().ToList().Where(x => x.Equals(name)).Cast<int>().First();
return _bits[index];
}
}
Now it works, crazily enough. But that LINQ chains looks positively atrocious, and it takes a while to decipher what it's actually doing.
Is there a cleaner, more efficient way of converting a generic Enum 'name' to its integer value? Or would I be better suited to use a Dictionary (or some other object) to represent the bit structure definitions?
As long as every TEnum you'd use derives from int (the default), and not from another number type, this will work:
public bool this[TEnum name]
{
get
{
int index = (int)(object)name;
return _bits[index];
}
}
If you want to support enums derived from smaller types (and enums that only use values within the range supported by int), I'd use:
public bool this[TEnum name]
{
get
{
int index = Convert.ToInt32(name);
return _bits[index];
}
}
(fully supporting enums derived from types that can't implicitly be converted to int, like uint, long, and ulong, gets more complicated, because BitArray's indexer uses an int)
I think a bit of OOP would make your life easier. You can introduces classes that represent the data you receive, and has meaningful property names. Each class could accept your BitArray into constructor and parse it into properties.
Further in your program you could use these classes instead of fiddling with bits.
As FrankPI suggested in the comments, why not use an enum whose values really represent each bit, rather than using an intermediate BitArray?
[Flags]
public enum RecordFlags { FLAG1 = 0x1, FLAG2 = 0x2, FLAG3 = 0x4, FLAG4 = 0x8, FLAG5 = 0x10, VALIDATED = 0x8000 };
var readFlags = (RecordFlags) ((bytes[0] << 8) | bytes[1]);
bool hasFlag2 = (readFlags & RecordFlags.Flag2) != 0;

How to return a string[] containing values of an Enum

I want to create a dynamic GUI that lists all of an Enum's options as buttons. So, I need a way to pass an Enum type to a method and get back a string array of all the options that enum type can be.
For example, given an Enum declaration in the file Foo.cs:
public Enum Fruits {
Apple,
Orange,
Peach
};
public class Foo { ... }
I want this returned:
{ "Apple", "Orange", "Peach" }
I have gone through several permutations of code. Right now I have the following but I am getting an error "Type or namespace name 'enumeratedType' cannot be found"
public static string[] EnumToStringArray (System.Type enumeratedType) {
int enumSize = sizeof(enumeratedType);
string[] enumStrings = new string[enumSize];
for (int i = 0 ; i < enumSize ; i++) {
enumStrings[i] = enumeratedType.getValues()[i].toString();
}
return enumStrings;
}
Is what I am trying to do possible? I have tried several complete rewrites based on information in this question Using sentinal values in C# enum (size of enum at compile time)? but I couldn't get it to work.
string[] names = Enum.GetNames(typeof(Fruits));
You could use something like
public static IEnumerable<string> EnumToStringArray(Type enumeratedType) {
if (!enumeratedType.IsEnum)
throw new ArgumentException("Must be an Enum", "enumeratedType");
return Enum.GetNames(enumeratedType);
}
but even that is needless, since Enum.GetNames(...) itself throws an ArgumentException if the given type is no Enum. (Thanks #Alexander Balte).
So you don't need an own function anyway. Simply Enum.GetNames(typeof(Fruits)) does the job, as others already mentioned.
You seem to have misunderstood the meaning of the sizeof keyword. It returns the number of bytes (each byte equals 8 bits) that the value type "takes up" when it's lined up with other values in unmanaged memory.
sizeof is not useful if you don't use unsafe context (like pointers).
For your Fruits type, sizeof(Fruits) returns 4 since the underlying iteger type is an Int32 (because that's the default when you don't specify otherwise). An Int32 requires 32 bits, therefore sizeof returns 4. It doesn't matter if you have 1, 2, 10, or 4294967296 different fruits.
Note that an enum can have multiple names pointing to the same value, like:
public enum Fruits {
Apple,
Orange,
Peach,
ChineseApple = Orange,
}
In this example, the enum contains four named constants, but two of them "map to" the same value. In that case, Enum.GetNames(typeof(Fruits)), will give you all four names.
But Enum.GetValues(typeof(Fruit)) will give you a list of four values of Fruit, two of which are identical. You can't know in advance if the two identical values will be displayed as Orange or ChineseApple, so don't use this approach if your enum has duplicates like that.

Other equivalent to enum?

I like to use enum as value holders whereever possible and I like it. It is easy to use i.e. just put a dot and see values. It is a good replacement of hard code some time.
But still it has some limitations. We cannot put special characters in values and some other.
Actually I am trying to make code reusable. Please guide me. Is there some technique or way that I can use some data structure like enum that is flexible but have no limitations.
You could use constants; they are immutable and can have any value.
See also: http://msdn.microsoft.com/en-us/library/ms173119.aspx
If I cannot use an enum for a set of predefined values, I use a class of static constants. They look much the same in use, but the values can be anything from a decimal to a string to a struct or class. I've done this for predefined cell color schemes in GridViews, much like the built-in Color class has predefined constant values. Mathematical and scientific constants such as e and Pi (if you wanted different values than are provided by the Math class), or the acceleration of gravity (9.8m/s2), or the speed of light (299,792,458m/s), can also be specified in this way.
If you think you can't use Enums because you need to store predefined string values, try this handy trick using the System.ComponentModel Description attribute:
public Enum MyStrings
{
[Description("This is string one")] StringOne,
[Description("This is a different string")] StringTwo,
...
}
To get the strings out, you simply examine the Description attribute, the code for which is a little messy but can be easily hidden behind an extension method:
public static string GetDescription(this Enum enumValue)
{
object[] attr = enumValue.GetType().GetField(enumValue.ToString())
.GetCustomAttributes(typeof (DescriptionAttribute), false);
return (attr.Length > 0)
? ((DescriptionAttribute) attr[0]).Description
: String.Empty;
}
Usage:
var stringOne = MyStrings.StringOne.GetDescription(); //"This is string one"
In this case, you can also consider using a Resource file. The value of the string can be changed from outside the scope of the program, without a recompile.
Not sure what exactly you need (re: "special characters"), but you could simply use some constants and put them into a static class, e.g:
public static class MyConstants
{
/// <summary>documentation here</summary>
public const string ValueA = "somevalue";
/// <summary>documentation here</summary>
public const string ValueB = "something else with special characters &#";
// etc.
}
Usage:
var x = MyConstants.ValueB;
One issue you might find with enums and more especially constants is that if you change the source assembly which defines the enum or constant, but don't recompile dependent assemblies, you'll end up mismatching in the source and dependent assemblies. For example:
public const int myConst = 5;
You later change this to:
public const int myConst = 10;
In the source assembly, which was rebuilt, it's 10. But it's 5 in any dependent assemblies that were not rebuilt.
To avoid this, use readonly instead of const. For example:
public readonly int myConst = 5;
This is different than a const, which is more like a C++ #define which causes the value to be placed directly in code. Readonly will cause a lookup at runtime, so if you don't recompile your dependent assemblies you'll still get the correct, updated value.

Enum vs Constants/Class with Static Members?

I have a set of codes that are particular to the application (one to one mapping of the code to its name), and I've been using enums in C# to represent them. I'm not sure now if that is even necessary. The values never change, and they are always going to be associated with those labels:
Workflow_Status_Complete = 1
Workflow_Status_Stalled = 2
Workflow_Status_Progress = 3
Workflow_Status_Complete = 4
Workflow_Status_Fail = 5
Should I use an enum or a class with static members?
Static members of type int seems to be inferior to an enum to me. You lose the typesafety of an enum. And when debugging you don't see the symbolic name but just a number.
On the other hand if an entry consists of more than just a name/integervalue pair a class can be a good idea. But then the fields should be of that class and not int. Something like:
class MyFakeEnum
{
public static readonly MyFakeEnum Value1=new MyFakeEnum(...);
}
Use an enum. Even though your codes never change, it will be difficult to know what the value represents just by inspection. One of the many strengths of using enums.
enum RealEnum : uint
{
SomeValue = 0xDEADBEEF,
}
static class FakeEnum
{
public const uint SomeValue = 0xDEADBEEF;
}
var x = RealEnum.SomeValue;
var y = FakeEnum.SomeValue;
// what's the value?
var xstr = x.ToString(); // SomeValue
var ystr = y.ToString(); // 3735928559
Not even the debugger will help you much here, especially if there are many different values.
Check out the State Pattern as this is a better design. With the idea you are using you'll end up with a large switch/if-else statement which can be very difficult to keep up.
I would lean towards enums as they provide more information and they make your codes "easier to use correctly and difficult to use incorrectly". (I think the quote is from The Pragmatic Programmer.

Categories

Resources