How to use Flags attribute? - c#

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
under­neath, and as do all inte­gers
in C# an enum has a default value of 0
when first cre­ated. So if 0 is not
mapped to an enu­mer­a­tion con­stant
then your enum will be instan­ti­ated
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.

Related

Is it possible in GraphQL to send an Enum with multiple values

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

Missing the first option when use List<T> in FormFlow,BotFramework

I write a FormFlow demo by review the guidelines https://docs.botframework.com/en-us/csharp/builder/sdkreference/forms.html, it work well.
In the demo "Simple Sandwich Bot" , Sandwich.cs , there are enum:
public List Toppings;
public List Sauce;
public enum ToppingOptions
{
Avocado, BananaPeppers, Cucumbers, GreenBellPeppers, Jalapenos,
Lettuce, Olives, Pickles, RedOnion, Spinach, Tomatoes
};
public enum SauceOptions
{
ChipotleSouthwest, HoneyMustard, LightMayonnaise, RegularMayonnaise,
Mustard, Oil, Pepper, Ranch, SweetOnion, Vinegar
};
when the code is running, and to choice ToppingOptions and SauceOptions,
the first option is missing.Is this a bug?
a picture to show the result
First of all, in the example they declare the list as a 'ToppingOptions' value, use List<ToppingOptions> instead of List only, if it doesn't work still, try to change the first value of the enums and set it = 1, and keep the others like that
public enum ToppingOptions
{
Avocado = 1, BananaPeppers, Cucumbers, GreenBellPeppers, Jalapenos,
Lettuce, Olives, Pickles, RedOnion, Spinach, Tomatoes
};
public enum SauceOptions
{
ChipotleSouthwest = 1, HoneyMustard, LightMayonnaise, RegularMayonnaise,
Mustard, Oil, Pepper, Ranch, SweetOnion, Vinegar
};
As you said in the comment, the guidlines is describe:"If a field is based on an enum and it is not nullable, then the 0 value in the enum is considered to be null and you should start your enumeration at 1."

Adding a subcategory to a PropertyGrid property from a unchangable class

I have an existing class, which contains properties similar to this one:
private int _someprop = 6;
[Display(Name = "SomeDisplayName", Order = 0, Description = "Description", GroupName="GroupName")]
[GridCategory("Parameters")]
public int SomeProp
{
get { return _someprop ; }
set { _someprop = value; }
}
I would like to have all of these properties displayed in a PropertyGrid, with the addition of a subcategory class for each one, which contains 3 properties - min, max and step (numeric values). Having a subcategory class with boolean and enum values will also be great. The issue is that the original class, which contains the 'SomeProp' property should not be changed in any way, since it is referenced directly from another program. The other requirement of this scenario is that all of the subcategory properties should also be accessible.
This is a screenshot of the expected result:
http://img542.imageshack.us/img542/5862/hfox.png
Is there any way to achieve this ?
Edit:
The idea is to set the values from the property grid. The scenario is the following:
I have a property grid with list of parameters. Lets say that the parameter is of type int. I would like to be able to optimize this parameter. This means that the user should be able to input a start value (min), end value (max) and a step value to the main property grid. From there I need to retrieve the user input values for min, max and step, and create a list of variations.
An example will be:
If the user inputs min = 10, max = 20, step = 2, then I should be able to retrieve those values in the code behind and create a list of possible inputs for the main property (which will be 10, 12, 14, 16, 18, 20). Then using this list I can make the optimization logic.
The initializing values of min, max and step should be as follows:
min = main property default value, max = main property default value, step = 1. So basically all values will be coming from the main property default value (which is 6 in the code snippet). From there user should be able to change the min, max and step properties. In that case I do not care if the user is able to change the main property (6) or not, since I will need all the variations between min, max with the particular step.

XML Serialization of Enums Without Default Values

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.

Trouble with an enumeration as a key in a Dictionary collection

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);

Categories