I have about 30 different flagged enums that I would like to put into an array for indexing and quick access. Let me also claify that I do not have 1 enum with 30 values but I have 30 enums with differing amounts of values.
The goal would be to add them to an array at a specifed index. This way I can write a functions in which I can pass the array index into for setting particuler values of the enum.
Updated:
Here is an example of what I am wanting to do.
enum main(
enum1 = 0,
enum2 = 1,
enumn = n-1 ) - this has indexs which would match the index of the associated enum
[flag]
enum1(value1=0, value2=1, value3=2, value4=4...)
[flag]
enum2("")
[flag]
enum2("")
since I am using flagable enums I have a class like the following
public static class CEnumWorker
{
public static enum1 myEnum1 = enum1.value1;
public static enum2 myEnum2 = enum2.value1;
public static enumN myEnumN = enumN.value1;
//I would then have functions that set the flags on the enums. I would like to access the enums through an array or other method so that I do not have to build a large switch statement to know which enum I am wanting to manipulate
}
Since you have 30 different types of enums, you can't create a strongly typed array for them. The best you could do would be an array of System.Enum:
Enum[] enums = new Enum[] { enum1.Value1, enum2.Value2, etc };
You would then have to cast when pulling an enum out of the array if you need the strongly typed enum value.
If I understand correctly, you would have to do:
object[] enums = new object[30];
enums[0] = Enum1.Value1;
enums[1] = Enum2.AnotherValue;
But then you would have to access like this (not strongly typed, and easy to reference the wrong index):
if ((Enum1)enums[0] == Enum1.Value1)
...
In .NET 4, you could use the Tuple:
var enums = new Tuple<Enum1, Enum2>(Enum1.Value1, Enum2.AnotherValue);
if (enums.Item1 == Enum1.Value1)
...
...but I wouldn't recommend it for so many (30) enums, and I think there's even a limit of 8 or so. You can also create your own class:
class Enums
{
public Enum1 Enum1 { get; set; }
public Enum2 Enum2 { get; set; }
}
Enums enums = new Enums();
enums.Enum1 = Enum1.Value1;
enums.Enum2 = Enum2.AnotherValue;
if (enums.Enum1 == Enum1.Value1)
...
I would recommend the last way because you're using a reference type, you're not dependent on index position, you can give the properties whatever name you want, and it's strongly typed. The only thing you "lose" is the ability to easily iterate through the list, but you can achieve that with Reflection if you really need to.
You could always use good old object[], but that means doing a lot of casting.
Enum provides two mechanisms for converting an integer to an enum value - the GetValues() method and plain casting:
enum EnumA { A1, A2, A1234 }
enum EnumB { B00, B01, B02, B04 }
class Program
{
static void Main(string[] args)
{
EnumA a = ((EnumA[])Enum.GetValues(typeof(EnumA)))[0];
Console.WriteLine(a);
EnumB boa = (EnumB)3;
Console.WriteLine(boa);
}
}
I'm not quite sure why you want to create your own arrays if you can use one of these mechanisms to get an enum from an int.
Related
This is probably an incredibly dumb question but: I have a function that takes in a string, and I want to make sure that the string is a constant from a specific class. Essentially the effect I'm looking for is what enums do:
enum MyEnum {...}
void doStuff(MyEnum constValue) {...}
Except with strings:
static class MyFakeStringEnum {
public const string Value1 = "value1";
public const string Value2 = "value2";
}
// Ideally:
void doStuff(MyFakeStringEnum constValue) {...}
// Reality:
void doStuff(string constValue) {...}
I know this can technically be achieved by doing some thing like
public static class MyFakeStringEnum {
public struct StringEnumValue {
public string Value { get; private set; }
public StringEnumValue(string v) { Value = v; }
}
public static readonly StringEnumValue Value1 = new StringEnumValue("value1");
public static readonly StringEnumValue Value2 = new StringEnumValue("value2");
}
void doStuff(MyFakeStringEnum.StringEnumValue constValue) {...}
But it feels kind of overkill to make an object for just storing one single value.
Is this something doable without the extra code layer and overhead?
Edit: While a enum can indeed be used for a string, I'd like to avoid it for several reasons:
The string values may not always be a 1:1 translation from the enum. If I have a space in there, different capitalization, a different character set/language, etc. I'd have to transform the enum in every function where I want to use it. It might not be a lot of overhead or a performance hit in any way, but it still should be avoided--especially when it means that I'm always mutating something that should be constant.
Even if I use a separate string array map to solve the above function, I would still have to access the translations instead of just being able to use the enum directly. A map would also mean having two sources for the same data.
I'm interested in this concept for different data types, ex. floats, ulongs, etc. that cannot be easily represented by enum names or stored as an enum value.
As for string -> enum, the point of using an enum in the first place for me is that I can rely on intellisense to give me a constant that exists; I don't want to wait until compile time or runtime to find out. Passing in an actual string would be duck typing and that's something I definitely don't want to do in a strongly typed language.
I would suggest you create an enum and parse the string value into an enum member.
You can use the Enum.Parse method to do that. It throws ArgumentException if the provided value is not a valid member.
using System;
class Program
{
enum MyEnum
{
FirstValue,
SecondValue,
ThirdValue,
FourthValue
}
public static void doStuff(string constValue)
{
var parsedValue = Enum.Parse(typeof(MyEnum), constValue);
Console.WriteLine($"Type: { parsedValue.GetType() }, value: { parsedValue }");
}
static void Main(string[] args)
{
doStuff("FirstValue"); // Runs
doStuff("FirstValuesss"); // Throws ArgumentException
}
}
I have an enum on helper library in my solution.
For example
public enum MyEnum
{
First,
Second
}
I want to use MyEnum in a few another project. I want to decorate this enum in each project with own attribute like this:
public enum MyEnum
{
[MyAttribute(param)]
First,
[MyAttribute(param2)]
Second
}
How to decorate enum from another library with own local attribute?
You can't do what you've described - the best you can do is to create a new Enum that uses the same set of values. You will then need to cast to the "real" enum whenever you use it.
You could use T4 templates or similar to generate the attributed enum for you - it would be much safer that way as it would be very easy to map the wrong values, making for some very subtle bugs!
Linqpad Query
enum PrimaryColor
{
Red,
Blue,
Green
}
enum AttributedPrimaryColor
{
[MyAttribute]
Red = PrimaryColor.Red,
[MyAttribute]
Blue = PrimaryColor.Blue,
[MyAttribute]
Green = PrimaryColor.Green
}
static void PrintColor(PrimaryColor color)
{
Console.WriteLine(color);
}
void Main()
{
// We have to perform a cast to PrimaryColor here.
// As they both have the same base type (int in this case)
// this cast will be fine.
PrintColor((PrimaryColor)AttributedPrimaryColor.Red);
}
Attributes are compile-time additions (metadata) to code. You can not modify them when using the compiled code assembly.
(Or perhaps you could if you are a diehard low-level IL wizard, but I certainly am not...)
If your enum values require modification or parameters at various places, then you should consider other solutions, e.g. a Dictionary or even a Database Table.
E.g. using a Dictionary:
var values = new Dictionary<MyEnum, int>()
{
{ MyEnum.First, 25 },
{ MyEnum.Second, 42 }
};
var valueForSecond = values[MyEnum.Second]; // returns 42
You can do something like this, but it will be tedious.
The idea is to use your project settings to allow the change when you import the enum in a new project.
First, you will need 2 attributes:
// This one is to indicate the format of the keys in your settings
public class EnumAttribute : Attribute
{
public EnumAttribute(string key)
{
Key = key;
}
public string Key { get; }
}
// This one is to give an id to your enum field
[AttributeUsage(AttributeTargets.Field)]
public class EnumValueAttribute : Attribute
{
public EnumValueAttribute(int id)
{
Id = id;
}
public int Id { get; }
}
Then, this method:
// This method will get your attribute value from your enum value
public object GetEnumAttributeValue<TEnum>(TEnum value)
{
var enumAttribute = (EnumAttribute)typeof(TEnum)
.GetCustomAttributes(typeof(EnumAttribute), false)
.First();
var valueAttribute = (EnumValueAttribute)typeof(TEnum).GetMember(value.ToString())
.First()
.GetCustomAttributes(typeof(EnumValueAttribute), false)
.First();
return Settings.Default[String.Format(enumAttribute.Key, valueAttribute.Id)];
}
I did not check if the type is correct, not even if it finds any attributes. You will have to do it, otherwise you will get an exception if you don't provide the right type.
Now, your enum will look like that:
[Enum("Key{0}")]
public enum MyEnum
{
[EnumValue(0)] First,
[EnumValue(1)] Second
}
Finally, in your project settings, you will have to add as many lines as the number of members in your enum.
You will have to name each line with the same pattern as the parameter given to EnumAttribute. Here, it's "Key{0}", so:
Key0: Your first value
Key1: Your second value
etc...
Like this, you only have to change your settings values (NOT THE KEY) to import your enum and change your attributes to a project to another.
Usage:
/*Wherever you put your method*/.GetEnumAttributeValue(MyEnum.First);
It will return you "Your first value".
In C# if I use a struct like shown below and do an equality comparison , values of the fields of the struct would be compared and I would get a result true if all the fields have same value.This is the default behaviour.
struct PersonStruct
{
public PersonStruct(string n,int a)
{
Name = n;Age = a;
}
public string Name { get; set; }
public int Age { get; set; }
}
var p1 = new PersonStruct("Jags", 1);
var p2 = new PersonStruct("Jags", 1);
Console.WriteLine(p1.Equals(p2)); //Return True
In case of class same thing would return a value false as it is a reference type.
class PersonClass
{
public PersonClass(string n, int a)
{
Name = n; Age = a;
}
public string Name { get; set; }
public int Age { get; set; }
}
var pc1 = new PersonClass("Jags", 1);
var pc2 = new PersonClass("Jags", 1);
Console.WriteLine(pc1.Equals(pc2));//Returns False
I understand the above concept.My question is considering the above scenario is it a good idea to use structs in such simple cases instead of a class ? I have commonly seen people implement classes in such cases(e.g. simple DTOs) and do all the extra stuff to implement equality operators (such as IEquatable and overridden equals method) .
Is my understanding correct or am I missing something here ?
You should avoid the default implementation of equality for structs. If your structs contain reference type fields (as PersonStruct does) then reflection is used to compare corresponding fields for equality, which is relatively slow. You should also implement IEquatable<T> for your structs since calling the object.Equals(object) method will cause boxing for both the source and argument struct. This will be avoided if the call can be resolved to IEquatable<PersonStruct>.
There is a whole article about this in MSDN.
✓ CONSIDER defining a struct instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.
X AVOID defining a struct unless the type has all of the following characteristics:
It logically represents a single value, similar to primitive types (int, double, etc.).
It has an instance size under 16 bytes.
It is immutable.
It will not have to be boxed frequently.
In all other cases, you should define your types as classes.
Related:
When do you use a struct instead of a class?
Is there a way to optionally force a [Flags] enum to be "non-Flags" for specific uses?
For example, say I have
enum MyEnum {
X ,
Y ,
Z
}
Now let's say I have two classes A and B. Class B will mostly be used within an IEnumerable<B>. Class A is responsible for parsing this list, but only when the enum matches a particular value;
class B {
MyEnum MyProperty { get; set; }
}
class A {
MyEnum Target = MyEnum.C;
void DoSomething(IEnumerable<B> list) {
for (var b in list) {
if (b.MyProperty == this.Target) {
// Do Some Work
}
}
}
}
Now suppose I want class A to be able to work with multiple types of B. I could add the [Flags] attribute to my enum and do something like this:
[Flags]
enum MyEnum {
None = 0,
X = 1,
Y = 2,
Z = 4
}
class B {
MyEnum MyProperty { get; set; }
}
class A {
MyEnum Target = MyEnum.X | MyEnum.Z;
void DoSomething(IEnumerable<B> list) {
for (var b in list) {
if (this.Target.HasFlag(b.MyProperty)) {
// Do Some Work
}
}
}
}
However, class B's MyProperty can now be used as a flag, which is a problem because there's no such thing as a MyEnum.X | MyEnum.Y in the context of B.MyProperty. It makes sense within A because I am targeting various kinds of class B.
The work around that I've come up with is this:
enum MyEnum {
None = 0,
X = 1,
Y = 2,
Z = 4
}
[Flags]
enum MyEnumTarget {
None = 0,
X = 1,
Y = 2,
Z = 4
}
class B {
MyEnum MyProperty { get; set; }
}
class A {
MyEnumTarget Target = MyEnumTarget.X | MyEnumTarget.Z;
void DoSomething(IEnumerable<B> list) {
for (var b in list) {
if (this.Target.HasFlag((MyEnumTarget)b.MyProperty)) {
// Do Some Work
}
}
}
}
While this works, it's definitely messy. I now have to keep track of two different enums. Any change I make in one, I have to make in the other and I have to make sure that the values are syncronized. On top of that I now have to cast to MyEnumTarget to be able to pass the value to Enum.HasFlag. Granted I could do bit-wise operations but then its not always so obvious what the intent is. Either way, I'd still need two "matching" enums.
Is there no better way to do to this? Is there some way to use a single enum type and force some sort of [NoFlags] attribute on B.MyProperty. Or is having the two enums considered the best way / good practice?
I'm using C#6.0 if that matters
Fundamentally, each enum type either is designed to have be a bit mask, or isn't. Options you might consider:
Two separate enums, as per your code
One non-flags enum, but make A.Property a List<MyEnum> or similar
One flags enum, but make the B.Property setter validate that only a single bit is set, throwing an ArgumentException otherwise
What's different between the two uses? It sounds like these should be two different enums because their meanings are different. The contracts of their use are different. If these were classes, I would suggest applying the Interface Segregation Principle, because they are used in a different way by different clients.
As these are enums, you can either wrap them in classes with interface segregation, or at least distinguish between the two enums.
Is there any way that I can change enum values at run-time?
e.g I have following type
enum MyType
{
TypeOne, //=5 at runtime
TypeTwo //=3 at runtime
}
I want at runtime set 5 to TypeOne and 3 to TypeTwo.
As others have pointed out, the answer is no.
You could however probably refactor your code to use a class instead:
public sealed class MyType
{
public int TypeOne { get; set; }
public int TypeTwo { get; set; }
}
...
var myType = new MyType { TypeOne = 5, TypeTwo = 3 };
or variations on that theme.
Just refer to MSDN help HERE
An enumeration type (also named an enumeration or an enum) provides an efficient way to define a set of named integral constants that may be assigned to a variable.
Also HERE
In the Robust Programming Section - Just as with any constant, all references to the individual values of an enum are converted to numeric literals at compile time.
So you need to realign your idea of Enum and use it accordingly.
To answer your question - No it is not possible.
Enums are compiled as constant static fields, their values are compiled into you assembly, so no, it's not possible to change them. (Their constant values may even be compiled into places where you reference them.)
Eg take this enum:
enum foo
{
Value = 3
}
Then you can get the field and its information like this:
var field = typeof(foo).GetField("Value", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
Console.WriteLine(field.GetValue(null));
Console.WriteLine(field.Attributes);