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.
Related
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
I have enums GroupTypes which I add to Types property.
There can be either Up/Down or both Up And Down types.
This is my code:
public enum GroupTypes: int {
Down = 0,
Up = 1,
}
[Column("types")]
[JsonProperty(PropertyName = "types")]
public GroupTypes[] Types {
get;
set;
}
// e.g.
var group = new Group() {
Name = "Group",
Types = new GroupTypes[] {
GroupTypes.Up
},
OrganizationId = Organization.Id,
};
However when I post them to database I get 500 error.
It seems correct to me and I am not sure what goes wrong.
In my database the type for this column is: "types" int4[] NULL and I expect them to be saved as array ( [0,1] or [1] or [0])in the database . What I am misisng here?
Before adding types, post method worked fine so I am assuming they are the problem but it seems like I define them correctly. I am using DBeaver and PostgreSQL
It is usually a good idea to use Flags enum & bitwise operations
Your case should be like this:
[Flags]
public enum GroupTypes:
{
None = 0,
Down = 1,
Up = 2,
DownAndUp = Down | Up
}
As a result, You need to save single value only instead of list of values.
If I were you, I wouldn't use an array to reflect that model. It'd be much better to use Up, Down and Both, for instance, otherwise you have to deal with the fact that it could be [1], [0], [1, 0], [0, 1], four combinations for the three states you need to present.
Also, this would map more elegantly to a database. In fact, I pretty much would use a character or even a whole string to represent that data, which gives more semantic value in the database (you already calling the column type, which is pretty generic.
public enum Types : char
{
Down = 'D',
Up = 'U',
Both = 'B',
}
With all that said, I haven't answered your question, because I need more information on the error you're getting and how you are communicating with the database.
This question already has answers here:
Non-unique enum values
(8 answers)
Closed 9 years ago.
In .NET can you have multiple enum values for the same integer?
eg.
public enum PersonGender
{
Unknown = 0,
Male = 1,
Female = 2,
Intersex = 3,
Indeterminate = 3,
NonStated = 9,
InadequatelyDescribed = 9
}
In C#, this is allowed, as per the C# Language Specication, version 4. Section 1.10 Enums doesn't explicitly mention the possibility but, later on in section 14 Enums, 14.3, we see:
Multiple enum members may share the same associated value. The example
enum Color {
Red,
Green,
Blue,
Max = Blue
}
shows an enum in which two enum members - Blue and Max - have the same associated value.
That works fine. There is absolutely nothing wrong with the code you posted. It compiles just fine and works in code, with the caveat that
PersonGender.NonStated == PersonGender.InadequatelyDescribed
I found this StackOverflow post related to this question. I think there is a very sensible discussion of how this works. Non-unique enum values
Now, I might also add that it is my opinion this would be an ambiguous (and therefore improper) use of an enum. It's important to write code that makes sense to someone else reading it, and in this case, I would be put off by this enum.
I would suggest that an enum would not be a right thing to use in your context instead you can use create a class and methods which can resolve your purpose. Something like this in your class:-
class A
{
static readonly ABCD= new Dictionary<int,string>
{
{ 1, "X" },
{ 2, "X" },
{ 3, "Y" }
{ 4, "Y" }
}
}
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 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);