In C# it's possible to create an Enum with a Flags Attribute.(https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=netstandard-2.1)
This means that that an Enum can look like this:
[Flags]
enum EnumWithFlags
{
None = 0,
FlagOne = 1,
FlagTwo = 2,
FlagThree = 4
}
EnumWithFlags can have a value of 5, which means it will have both FlagThree and FlagOne.
Is this also possible with a Enum inputtype? And is there an example for this?
From the Schemas and Types:
Enumerations types are a special kind of scalar that is restricted to a particular
set of allowed values.
Basically, you have to define each combination of flags as a separate value if you want it to be an enumeration.
A better solution is probably to use a vector, where you can set multiple enum values in a list:
type Foo {
flags: [EnumWithFlags]
}
enum EnumWithFlags {
NONE
FLAG_ONE
FLAG_TWO
FLAG_TREE
}
An update, it has also been answered here
Related
This question already has answers here:
Create instance of unknown Enum with string value using reflection in C#
(2 answers)
Closed 3 years ago.
What I have is a string variable that is the name of a enum. I have the integer of the enum. How would I convert that into instance of the enum itself?
Enum TestEnum
{
One = 1,
Two = 2,
Three = 3
}
string str = "TestEnum";
int intValue = 2;
I see many posts that require you to have an instance of the enum to get it's like this highly upvoted answer.
I need to do this at runtime.
Edit:
I am trying to write a class that gets and sets settings in an api that has hundreds of enums that represent settings.
The enums break are categorized by 5 basic setting types represented by five enums. These enums are like:
DoubleValueEnum
IntegerValueEnum
BooleanValueEnum
StringValueEnum
These enums are pointers to settings of type double, integer, string, bool. I believe that underneath the hood they have a database that keeps a table like this:
Type key value Represents
------- ------ ------- ---------------------------------
Double 23 2.745 DoubleValueEnum.DrawingWidth
Integer 5 18 IntegerValueEnum.PenColor
Double 54 15.9245 DoubleValueEnum.GridMajorSpacing
For doubles there is no "lower" enum that it is pointing to. For integer there is a deeper enum like "PenNumber.Red = 1, PenColor.Green = 2.
Hypothetical pen color:
Enum PenColor
{
Red = 1,
Blue = 2,
}
Each of these enums have hundreds of values. Each of these enums has a prewritten function the gets or sets the enum:
GetDoubleEnumValue(int, option)
GetIntegerValueEnum(int, option)
GetBooleanValueEnum(int, option)
GetStringValueEnum(int, option)
SetXXXXXEnumValue(enum, value)
SetDoubleEnumValue(int, int)
SetIntegerValueEnum(int, int)
SetBooleanValueEnum(int, int)
SetStringValueEnum(int, int)
Real example:
SetIntegerValueEnum ((int)IntegerValueEnum.swDxfVersion, (int)swDxfFormat_e.swDxfFormat_R14);
For your given enum definition:
enum TestEnum
{
One = 1,
Two = 2,
Three = 3
}
enum TestEnum2
{
OnePoint1 = 1,
OnePoint2 = 2,
OnePoint3 = 3
}
Use Enum.Parse(Type, string) to parse the string value as an Enum value.
string str = "Two";
TestEnum valueAsEnum = (TestEnum)Enum.Parse(typeof(TestEnum), str);
However, you need to know they type of the Enum definition that you want to parse. If the exact type of the enum value is unknown, but you do know the potential types, then you can iterate through the types and test using the Enum.TryParse
string str = "Two";
object enumValue = null;
if (!Enum.TryParse(typeof(TestEnum), str, true, out enumValue))
Enum.TryParse(typeof(TestEnum2), str, true, out enumValue))
If you do not know the specific type of the enum but you do know the class name, you can use the Type.GetType Method to resolve the type
For this to work you do need to know the full namespace of type that you want to resolve, AND the assembly that the type is defined in must already be loaded.
The syntax to convert an int to an enum is discussed here: https://stackoverflow.com/a/56859286/1690217
In this example, we know that all of the enums reside in the API.Client.Enums namespace:
string str = "TestEnum";
int intValue = 2;
string ns = "API.Client.Enums";
Type enumType = Type.GetType($"{ns}.{str}");
// now we can parse the value:
object value = Enum.ToObject(enumType, (object)intValue);
Usually we do not need to bother with a lot of this conversion just to pass values between systems, the fact that the enum resolves to an integer means that for unknown types we should be able to write our logic to just deal with the integer, and only convert it back to a specific enum when you need it.
It looks like you are trying to use BitWise operations on Enum values to allow a single setting property to represent multiple optional states.
For this sir Enums have support built in if you use the Flags attribute:
There is a good SO dicussion that covers this too: What does the [Flags] Enum Attribute mean in C#?
Lets look at PenColor enum first:
[Flag]
enum PenColor : int
{
None = 0 // 0
Red = 1 << 0, // 1
Green = 1 << 1, // 2
Blue = 1 << 2 // 4
}
By defining the discrete enums with base-2 values, we can now use either bitwise operations on the PenColor enum, or we can use simple integer addition/subtraction:
PenColor cyan = PenColor.Green | PenColor.Blue;
int cyanInt = (int)PenColor.Green + (int)PenColor.Blue;
PenColor cyanCasted = (PenColor)cyanInt;
All of those statements will be equivalent. So potentially this syntax replaces your SetIntegerValueEnum, but it relies on the enum definition being implemented with base-2 values.
To test, this statement should be true:
SetIntegerValueEnum ((int)IntegerValueEnum.swDxfVersion, (int)swDxfFormat_e.swDxfFormat_R14)
== (int)IntegerValueEnum.swDxfVersion + (int)swDxfFormat_e.swDxfFormat_R14)
== IntegerValueEnum.swDxfVersion | swDxfFormat_e.swDxfFormat_R14
The last option will only work if the [Flags] attribute decorates the enum type definition.
You can then use this in switching logic or comparisons
PenColor cyan = PenColor.Green | PenColor.Blue;
bool hasBlue = cyan & PenColor.Blue == PenColor.Blue;
// you can also use the slower Enum.HasFlag
hasBlue = cyan.HasFlag(PenColor.Blue);
So System.Type has an instance method called Attributes.
public TypeAttributes Attributes { get; }
which returns an enum of type TypeAttributes. Here are some members of this enum:
public enum TypeAttributes {
AnsiClass = 0,
Class = 0,
AutoLayout = 0,
NotPublic = 0,
Public = 1,
NestedPublic = 2,
NestedPrivate = 3,
NestedFamily = 4,
NestedAssembly = 5,
NestedFamANDAssem = 6,
VisibilityMask = 7,
NestedFamORAssem = 7,
SequentialLayout = 8,
ExplicitLayout = 16,
LayoutMask = 24,
...
}
But on the other hand, Type class has provides too many properties for most of the stuff appear in this enum:
IsPublic
IsClass
IsNestedFamANDAssem
IsAutoLayout
...
So what exactly Type.Attributes is for? I guess it is not a bitmasked value, since it is an enum and it returns only a single member of enum. And this is not a static property on Type class,so what exactly does it do?
Type.Attributes is a bitmasked value. It even says so in the documentation.
enums are commonly used as Flag data types by decorating them with the Flags attribute.
And those properties of Type, like IsPublic, IsClass etc. just check those flags and return a boolean value. You can see it yourself by looking at the definitions using reflector.
IsPublic, for example does something like this:
public bool IsPublic {
get {
return ((this.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public);
}
}
Not all properties of Type necessarily represent one of the flags though (like IsEnum).
I guess it is not a bitmasked value
You guess wrong. It's marked as FlagsAttribute:
Indicates that an enumeration can be treated as a bit field; that is, a set of flags.
As you indicate, many of these are also available as properties. So, why is it exposed? Well, firstly, because it's the natural representation of this information. The properties (e.g. IsPublic) just hide the bit testing for you. And secondly, sometimes it's a more convenient value to pass around than an array of booleans.
It is bitmasked value where portions of the value represent partiular properties of the Type -
myType.Attributes & TypeAttributes.VisibilityMask gives you one of several Public/NonPublic/NestedPublic... values from the enum
myType.Attributes & TypeAttributes.LayoutMask gives you layout type (Sequential/Explicit/default)
and so on.
I have an enum:
[DataContract]
public enum Relationship
{
Spouse = 4,
ResidesWith = 1,
Parent = 2,
Other = 3,
PersonalGuarantor = 5,
CoApplicant = 6
}
As you can see, zero is not defined. I built my program around the idea that zero would never be defined in enums. That allows me to see which ones have been set from various comboBoxes, and which ones were set to a null value. If I set zero as the null value, there is no way to tell those two things apart, and it essential that I be able to.
Due to the lack of a default state, I get an error when I try to serialize the values.
Is there a way to have my xml serialize skip enums that have no value, or a way to avoid those errors? I really do not want to introduce a default value.
You need to use 0 as an enum value - make it a value that is not valid and that you check for (as you are already).
[DataContract]
public enum Relationship
{
Invalid = 0,
Spouse = 4,
ResidesWith = 1,
Parent = 2,
Other = 3,
PersonalGuarantor = 5,
CoApplicant = 6
}
Don't forget that enumerations are based on an integer type (their base type), so they will always have a value (value types cannot be null) and will default to 0. Making this explicit will also make things clearer in your codebase.
Protip: You can use negative values in enums as well.
I have some items in database. Each of'em can have many tags, like Browsable, or IsInMenu and so on. A friend of mine suggested to use enums with Flags attribute to create an extensible solution. So, I created a field in DB which takes an integer value, then I created this enum:
[Flags]
public enum ItemTags { Browsable = 2, IsInMenu = 4}
Now I'd like to be able to semantically get the list of some items this way:
public List<Item> GetItems(ItemTags tags)
{
/*
Code to get data from DB, something like,
return repository.GetList(tags);
*/
}
and in UI, I'd like to call:
List<Item> items = GetItems(ItemTags.Browsable | ItemTags.IsInMneu);
But I don't get the desired result. Am I going the right way?
By desired result, I mean this:
Values stored in database could be one of the 0, 2, 4, 6 values now. 0 means that the item is not in Menu and also not Browsable. 2 Means that item is Browable, but not in Menu. 4 means item is in Menu, but not Browsable. 6 means item is both Browsable and IsInMenu. Now when I call GetItems function, I don't get all the items which are browsable, in menu, or both browsable and in menu.
You need to use FlagsAttribute, see this MSDN article, and this usage example, and most importantly this stack overflow answer.
use the FlagsAttribute Class
Indicates that an enumeration can be
treated as a bit field; that is, a set
of flags.
[Flags]
public enum ItemTags
{
Default =0,
Browsable = 2,
IsInMenu = 4,
All = 6 // Browsable / IsInMenu
}
More here
note about enums:
an Enum by default has an int
underneath, and as do all integers
in C# an enum has a default value of 0
when first created. So if 0 is not
mapped to an enumeration constant
then your enum will be instantiated
with an invalid valid
You are missing the Flags attribute...
Your enum should be declared like this:
[Flags]
public enum ItemTags { Browsable = 2, IsInMenu = 4}
EDIT:
After your update, it looks fine. You should be more precise in what you mean with:
But I don't get the desired result.
The code you showed us looks fine. So either there is a problem elsewhere or the code you really use in your application and the code you showed us here are different.
I have a scenario where I'm using a Dictionary to hold a list of transaction types that a certain system accepts. The key in the Dictionary is an enum field, the value is an int.
At some point in the system, we're going to want to do something like this:
sqlCommand.Parameters.AddWithValue("#param", LookupDictionary[argument.enumField]);
When we look up the field in the dictionary, we're going to get the correct integer value to feed to the database. I've thought about actually using the enum int value for this, but that's not exactly right. We're interacting with a system where we need to feed a magic number in to represent the kind of update we're doing.
The code above works just fine. I have an initializer method that adds the known types:
LookupDictionary = new Dictionary<mynamespace.myproject.myclass.enumType, int>();
LookupDictionary.Add(enumType.entry1, 4);
LookupDictionary.Add(enumType.entry2, 5);
LookupDictionary.Add(enumType.entry3, 6);
This code also works fine.
But up above, before I actually get in to using the LookupDictionary, I validate that the request being made is actually set to an enum value we support. That's LookupDictionary's main reason to be, it holds the valid ones (there are valid enum entries that this method doesn't work with).
This is the code that doesn't work: the system fails to recognize that the enums match. In the debugger, I can see that the entries list in LookupDictionary does show that it has the value for entry2 - it just calls it like that, entry2. The incoming enumField on the other hand has the full namespace; mynamespace.myproject.myclass.enumType.entry2 - I imagine this is why it doesn't see them as being the same.
if (!LookupDictionary.ContainsKey(argument.enumField))
{
throw new InvalidOperationException("argument.enumField not valid in blahMethod.");
}
Did I mention that this is being passed across a WCF service? But I'm not using an auto-generated proxy ... both projects on both sides of the wire share the types as a project reference, and I build up my channel client in code.
Any ideas? Am I doing it wrong? Do Dictionaries with Enums as keys not work well? Is it a WCF thing?
Note: thanks for the suggestions regarding setting the enums up to contain the magic int. I wanted to set those in a configuration, however, as its possible that the "magic numbers" 4 5 and 6 might change down the road. So if I code them in to the enum as suggested:
public enum MyEnum
{
MyValue1 = 4,
MyValue2 = 5,
MyValue3 = 6
}
I lose the ability to write a method that sets up the magic numbers in the future at run time; instead it would require a code change.
Instead of using the enum as the key, use the integer representation of the enum.
For instance:
LookupDictionary = new Dictionary<int, int>();
LookupDictionary.Add((int)enumType.entry1, 4);
LookupDictionary.Add((int)enumType.entry2, 5);
LookupDictionary.Add((int)enumType.entry3, 6);
That way, you can use the same 'ContainsKey' method of the dictionary. I'm not sure this is much better performance than a List<int>
You shouldn't need a lookup table here at all:
public enum MyEnum
{
MyValue1 = 4,
MyValue2 = 5,
MyValue3 = 6
}
// Sample usage
MyEnum firstEnum = MyEnum.MyValue1;
int intVal = (int)firstEnum; // results in 4
// Enum Validation
bool valid = Enum.IsDefined(typeof(MyEnum), intVal); // results in true
Can you considered typing your enumeration explicitly as int (or whatever the underlying type is) and then setting the value of each of your enumerations to the database value? You've already tightly coupled the enumeration to the database, so either the relationship will be dictated in C# (current hard-coding) or by SQL (perhaps a proc that returns the ID as well as a string that can be parsed into an enumeration.)
Using the assumption that your enumeration is an int...
enum enumType {
entry1 = 4,
entry2 = 5,
entry3 = 6
}
When adding your parameter you would then just cast as the enum's underlying type.
sqlCommand.Parameters.AddWithValue("#param", (int)argument.enumField);
You can explicitly set the values of the enum using the syntax
enum ArgumentTypes {
Arg1 = 1;
Arg2 = 3;
Arg3 = 5;
}
You don't need to keep each value sequential in the enum for this syntax to work.
To validate that only parameters that are valid for the method are ever used, try this sample code. Note I suggest using an ArgumentException over an InvalidOperationException in this context.
public void DoDbWork(ArgumentTypes argType, object otherParameter)
{
if (argType == ArgumentTypes.Arg3) {
throw new ArgumentException("Argument of value " + argType + " is not valid in this context", "argType");
}
// Handle db transaction here
}
To add the int value as the parameter:
cmd.Parameters.AddWithValue("#paramName", (int)argType);