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.
Related
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 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);
In C# I know we can't we assign objects to an Enum. The functionality I'm after is when an Enum is declared, it triggers off an event.
So instead of having
enum MyEnum
{
string, int, etc
}
I could have
enum MyEnum
{
classType1, classType2
}
This would then also allow the classes classType1/classType2 constructor to be called which could (for example) be useful for logging for when the enum is declared.
Another way of presenting my issue could be
enum MyEnum
{
string1
{
//logic
},
string2
{
//logic
}
}
Is there a work around for this?
Instead of enum you can use a static class with static properties, it can be used same as an enum but you can write code inside getter and setter.
U could use properties instead of enum (then u can write ur own logic which will be called after/before assigning the variable). The enum structure should be used to create flags-like stuff.
private string _myVar;
public string MyVar
{
get { return _myVar; }
set
{
// logic 1 here
_myVar = value;
// logic 2 here
}
}
No work around as, I think, your expectation does not match the language. For example consider what would happen with:
if (myEnumValue == MyEnum.classType1)
Your question implies that on the right a class of 'classType1' would be instantiated for the equality test and then the result would depend on that types implementation of equality. This is confusing when the item on the left is an enum ... but with your assumption it is an object of type 'classType1' which implies that both the left and right are temporary objects.
You can see that this could not work.
But ... what I think your really after is a factory to create objects from an enum. Whole other question that raised other questions (sorry). An enum like this implies a state ... so if you have a state why does that state need an enum? A big question in itself, check out the state pattern.
Hope I've helped.
An enum is a Value type based on an Int## type. So this is the same as asking: can I get some logic into the assignment of int i = 7; and the direct answer is No.
Neither can you base an enum on anything other than an integer type.
But your requirement seems to be with tracking instances. That's easy with properties. But you can only do it for a specific property, not build it into the Type.
Enums are barely integers with comprehensive labels. As far as I know, what you are looking for cannot be done using enums.
However, and as stated by #Grumbler85, this behavior can be simulated using factories.
A factory is a special type of object that are used to create instances of other objects.
The easiest way to implement a factory is using a switch statement but other ways exists (reflection for example). Here's a simple example of what you are looking for:
Class A
{
...
}
Class B
{
...
}
enum eKnownTypes
{
A,
B
}
Class Factory
{
/*
Implement Singleton here
....
*/
public object CreateInstance(eKnownTypes t)
{
/*
Raise any event needed here
...
*/
switch (t):
{
case eKnownTypes.A: return new A(); break;
case eKnownTypes.B: return new B(); break;
}
return null;
}
}
/*
Set Event Handlers here
Factory.Instance.CustomEvent += new EventHandler ...
....
*/
A objectA = Factory.Instance.CreateInstance(eKnownTypes.A) as A;
...
You can do it with an enum, but you could do
public struct MyType
{
public const int OneValue = 1;
public const int TwoValue = 2;
private static readonly MyType one = new MyType(OneValue);
private static readonly MyType two = new MyType(TwoValue);
private readonly value int;
private MyType(int value)
{
this.value = value;
}
public static One
{
get { return this.one; }
}
public static Two
{
get { return this.two; }
}
public static implicit operator int(MyType source)
{
return source.value;
}
}
To give you a class that behaves like an enum but is fully extendable.
for instance, you can do
var myType = MyType.One;
switch (myType)
{
case MyType.OneValue:
...
case MyType.TwoValue:
...
default:
...
}
The instances are immutable and can be accuarately tested for equality using the implemenation inhereted from object, i.e. reference quality.
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.