Loop through enum result property - c#

I have a model with a enum property. When I call my service, the model is returned back, and my enum-property contains the following data: Test1 | Test2 | Test3.
I want to loop through the propery and assign the values to a list.
How can I do this with an enum propery?
var form = await _formService.GetById();
That code above generates a result with a enum property called Sections with th data that I provided above, but I don't know how to loop through It to get the values.
Here is my Enum:
[Flags]
public enum Sections
{
Test1= 0,
Test2= 1,
Test3= 2,
Test4= 4,
}

Is this what you are looking for?
[Flags]
public enum Sections
{
Test1 = 0,
Test2 = 1,
Test3 = 2,
Test4 = 4,
}
public static List<Sections> getSectionsFromFlags(Sections flags)
{
var returnVal = new List<Sections>();
foreach (Sections item in Enum.GetValues(typeof(Sections)))
{
if ((int)(flags & item) > 0)
returnVal.Add(item);
}
return returnVal;
}

If you have defined enum like this
[Flags]
public enum Sections
{
Test1 = 0,
Test2 = 1,
Test3 = 2,
Test4 = 4,
}
Then
var someValue = Sections.Test1 | Sections.Test3 | Sections.Test4;
var values = Enum.GetValues(typeof(Sections))
.OfType<Sections>().Where(x=>(x&someValue)==x)
.ToArray();
values now contains all three value Sections.Test1 | Sections.Test3 | Sections.Test4
Another solution (from comments)
var values = Enum.GetValues(typeof(Sections))
.OfType<Sections>()
.Where(x=>someValue.HasFlag(x))
.ToArray();
Last one Is most correct, I think.

Related

Setting enum flags from integer value

CompBitsList companyBit;
public CompBitsList CompanyBit { get => companyBit; set => companyBit= value; }
[Flags]
public enum CompBitsList
{
None = 0
BitOption1 = 1,
BitOption2 = 2,
BitOption3 = 4,
BitOption4 = 8,
BitOption5 = 16,
BitOption6 = 32,
}
Lets say I have the integer value 22 that would contain the enum flags BitOption2, BitOption3 and BitOption5 (2+4+16). Is there a way to automate this so that I can pass the integer value and have the enum variable CompanyBit set automatically?
companyBit = CompBitsList.BitOption2 | CompBitsList.BitOption3 | CompBitsList.BitOption5
I'm not very familar with enums but I would prefer not to do the method above so any suggestions are appreciated. Thanks :)
You can just cast the int to an instance of CompBitsList.
CompBitsList companyBit = (CompBitsList)22;
companyBit.HasFlag(CompBitsList.BitOption2); // True
companyBit.HasFlag(CompBitsList.BitOption3); // True
companyBit.HasFlag(CompBitsList.BitOption5); // True
companyBit.HasFlag(CompBitsList.BitOption6); // False
You can also define a value on that enum that represents a combination of flags, if it makes sense and you'll be combining those flags a lot.
[Flags]
public enum CompBitsList
{
None = 0
BitOption1 = 1,
BitOption2 = 2,
BitOption3 = 4,
BitOption4 = 8,
BitOption5 = 16,
BitOption6 = 32,
BitOptions2And3And5 = BitOption2 | BitOption3 | BitOption5 //or just 22
}

How to use flags to check if something from the collection matches the flag

I'm trying to use flags to filter collection and retrive certain objects.
Perhaps the example will show the issue.
I defined a class and an enum.
public class ExampleFlagsDto
{
public int FlagId { get; set; }
public string Name { get; set; }
}
[Flags]
public enum FlagsTypes
{
None = 0,
Small = 1 << 0 ,
Medium = 1 << 1 ,
Normal = 1 << 2,
Large = 1 << 3,
LargeAndNormal = Normal | Large,
All = Normal | Medium | Small | Large,
}
Then I constructed a list as an example and tried to retrive 2 objects from the list.
var examples = new List<ExampleFlagsDto>()
{
new ExampleFlagsDto
{
FlagId = (int)FlagsTypes.Normal,
Name = "First"
},
new ExampleFlagsDto
{
FlagId = (int)FlagsTypes.Medium,
Name = "Second"
},
new ExampleFlagsDto
{
FlagId = (int)FlagsTypes.Large,
Name = "Third"
},
new ExampleFlagsDto
{
FlagId = (int)FlagsTypes.Small,
Name = "Forth"
},
};
var selected = examples.Where(C => C.FlagId == (int)FlagsTypes.LargeAndNormal).ToList();
foreach (var flag in selected)
{
Console.WriteLine(flag.Name);
}
Of course, it doesn't work. I know that when it comes to bits, (int)FlagTypes.LargeAndNormal would result in a sum of bits of Large and Normal. I have no idea how it has to look like bitwise, though.
I'm looking for a way to change the
examples.Where(C => C.FlagId == (int)FlagsTypes.LargeAndNormal).ToList();
to a solution that would result in selected having 2 objects from examples.
You could try this solution:
var selectedAll = examples.Where(C => (C.FlagId & (int)FlagsTypes.All) == (int)C.FlagId).ToList();

Enum.HasFlag is not working as expected [duplicate]

This question already has answers here:
HasFlag always returns True
(5 answers)
Closed 4 years ago.
I have a Enum with Flags like this:
[Flags]
public enum ItemType
{
Shop,
Farm,
Weapon,
Process,
Sale
}
Then I have several objects in a list with some flags set and some flags not set. It looks like this:
public static List<ItemInfo> AllItems = new List<ItemInfo>
{
new ItemInfo{ID = 1, ItemType = ItemType.Shop, Name = "Wasserflasche", usable = true, Thirst = 50, Hunger = 0, Weight = 0.50m, SalesPrice = 2.50m, PurchasePrice = 5, ItemUseAnimation = new Animation("Trinken", "amb#world_human_drinking#coffee#female#idle_a", "idle_a", (AnimationFlags.OnlyAnimateUpperBody | AnimationFlags.AllowPlayerControl)) },
new ItemInfo{ID = 2, ItemType = ItemType.Sale, Name = "Sandwich", usable = true, Thirst = 0, Hunger = 50, Weight = 0.5m, PurchasePrice = 10, SalesPrice = 5, ItemUseAnimation = new Animation("Essen", "mp_player_inteat#pnq", "intro", 0) },
new ItemInfo{ID = 3, ItemType = (ItemType.Shop|ItemType.Process), Name = "Apfel", FarmType = FarmTypes.Apfel, usable = true, Thirst = 25, Hunger = 25, Weight = 0.5m, PurchasePrice = 5, SalesPrice = 2, ItemFarmAnimation = new Animation("Apfel", "amb#prop_human_movie_bulb#base","base", AnimationFlags.Loop)},
new ItemInfo{ID = 4, ItemType = ItemType.Process, Name = "Brötchen", usable = true, Thirst = -10, Hunger = 40, Weight = 0.5m, PurchasePrice = 7.50m, SalesPrice = 4}
}
Then I go trough the list with a loop and ask if the flag ItemType.Shop is set or not, like this:
List<ItemInfo> allShopItems = ItemInfo.AllItems.ToList();
foreach(ItemInfo i in allShopItems)
{
if (i.ItemType.HasFlag(ItemType.Shop))
{
API.consoleOutput(i.Name);
}
}
This is the output of my loop - it shows all items in the list, and the .HasFlag method always returns true in this case.
Wasserflasche
Sandwich
Apfel
Brötchen
Try to assign values to your enum
[Flags]
public enum ItemType
{
Shop = 1,
Farm = 2,
Weapon = 4,
Process = 8,
Sale = 16
}
Here are some Guidelines for FlagsAttribute and Enum (excerpt from Microsoft Docs)
Use the FlagsAttribute custom attribute for an enumeration only if a bitwise operation (AND, OR, EXCLUSIVE OR) is to be performed on a numeric value.
Define enumeration constants in powers of two, that is, 1, 2, 4, 8, and so on. This means the individual flags in combined enumeration constants do not overlap.
You should assign values to your enums. All the flags attribute does is change how the ToString method works. I would use a bitwise operator to make it less likely to make a mistake:
[Flags]
public enum ItemType
{
Shop = 1 << 0, // == 1
Farm = 1 << 1, // == 2
Weapon = 1 << 2, // == 4
Process = 1 << 3, // == 8
Sale = 1 << 4 // == 16
}

c# enum names to filter on in a DropDownList instead of value

I have a list of enums that includes a enumeration called Default.
public enum Fruits { Default = Banana,
Banana = 1,
Orange = 2,
Grapefruit = 3 }
I need to populate a dropdownlist that excludes the Default field.
Html.DropDownList("fruitSelector",
Enum.GetValues(typeof(Fruits)).Cast<Fruits>()
.OrderBy(o => o.GetDescription())
.Where(o => o != Fruits.Default)
.Select(o => new SelectListItem() {Text = o.GetDescription(), Value = ((int) o).ToString()}), "-- All Fruits --",
new {#class = "form-control", #aria_describedby="sizing-addon1"})
when i try to filter on Fruits.Default it removes BOTH default and the Banana. How can i do a filter comparison where i only remove Default?
[[CORRECTION]] this enum duplicates my problem. I honestly don't understand the difference.
public enum Fruits
{
Default = Peaches,
Peaches = 1,
Bananas = 2,
Grapefruit = 3,
Apple = 101,
Watermellon = 102
}
or
public enum Fruits2
{
Default = Mangos,
Mangos = 1,
Dates = 2,
Figs = 3,
Apples = 101,
Limes = 102,
Grapes = 103
}
I don't think what you're trying to do is possible as it is. The problem is your Enum structure.
public enum Fruits
{
Default = Peaches,
Peaches = 1,
Bananas = 2,
Grapefruit = 3,
Apple = 101,
Watermellon = 102
}
You're saying value of Default is Peaches of which value in turn is 1. Which essentially is the same as (B is Peaches and A is Default:
int B = 1;
int A = B;
So when we use Enum.Parse(), it treats both the same, and picks the first value. You'll understand when you look at the following scenario. Run the following code, with your current Enum:
var deflt = Enum.Parse(typeof(Fruits), Fruits.Default.ToString());
var peach = Enum.Parse(typeof(Fruits), Fruits.Peaches.ToString());
Console.WriteLine(deflt);
Console.WriteLine(peach);
The output is going to be:
Default
Default
Then change your Enum to this:
public enum Fruits
{
Peaches = Default ,
Default = 1,
Bananas = 2,
Grapefruit = 3,
Apple = 101,
Watermellon = 102
}
And run the above two lines of code again. Your output this time will be:
Peaches
Peaches
That is, Parse() picks the first defined Enum when there's an equality like you have.
EDIT:
The above explanation is slightly incorrect, as pointed out in the comments below by George Alexandria. Please see his explanation:
You have the different output when use Peaches = Default , Default = 1, and Default = Peaches, Peaches = 1, because you invoke Enum.ToString in Console.WriteLine. If you look at the var deflt, var peach you will see that they are the same in the both cases and they are the value which name is the first by alphabetical.
But there is a workaround. From your initial code sample what I gather is you need a list of Enums, their descriptions, and their numerical values, am I correct? So, I would first just grab a list of strings excluding Default which is quite simple. Then iterate through the string list, and add to a list of your SelectListItem class objects.
var res = Enum.GetNames(typeof(Fruits))
.Where(x => x != "Default");
List<SelectListItem> list = new List<SelectListItem>();
foreach (string fruit in res)
{
string desc = EnumHelper<Fruits>.GetEnumDescription(fruit); // This is a utility method I use. You can get the description using your extension method.
int val = (int)Enum.Parse(typeof(Fruits), fruit);
list.Add(new SelectListItem { enumName = fruit, enumDesc = desc, enumVal = val });
}
And if you must have that OrderBy, after creating your SelectListItem list, sort it once again by Description.
You should compare enum values by their names, because Default and Banana are equal. So just try to retrieve names, filter them and parse them to values.
var res = Enum.GetNames(typeof(Fruits))
.Where(o => o != nameof(Fruits.Default))
.Select(o => Enum.Parse(typeof(Fruits), o))
.Cast<Fruits>().ToList();
It's your full example:
Html.DropDownList("fruitSelector",
Enum.GetNames(typeof(Fruits))
.Where(o => o != nameof(Fruits.Default))
.Select(o => Enum.Parse(typeof(Fruits), o)).Cast<Fruits>()
.OrderBy(o => o.GetDescription())
.Select(o => new SelectListItem() { Text = o.GetDescription(), Value = ((int)o).ToString() }), "-- All Fruits --",
new { #class = "form-control", #aria_describedby = "sizing-addon1" })

Ordering list by 3 numbers

I have a List<> with objects, that hold multiple fields, which are mostly numbers. I want to sort this list, by 3 of those numbers. I've tried this:
list = list.OrderBy(x => x.Val3).ThenBy(x => x.Val2)
.ThenBy(x => x.Val1).ToList();
which works fine, but only for the first two order/thenbys. The third one seems to not get run at all. I can sort for any combination of two of those values just fine, but the third on is always ignored.
I haven't tried the non LINQ approach yet, because I'm simply curious where the problem here is. Can't you sort for 3 values? What's the problem here? In case this matters in any way, 3 is a ushort, while 2 and 1 are uints.
I am not sure if there are any better solutions. If I were you, I would weight the value2 by multiply a big value. Just like:
list = list.OrderBy(x => x.Val3).ThenBy(x => x.Val2 * 10000 + x.Val1).ToList();
I think you can try this hack:
list = list.OrderBy(x => x.Val2).OrderBy(x => x.Val3).ThenBy(x => x.Val1).ToList();
This doesn't solve the problem because it just works. However, perhaps you can compare your code to this and see how it differs?
public class Foo
{
public string Name { get; set; }
public uint Val1 { get; set; }
public uint Val2 { get; set; }
public ushort Val3 { get; set; }
}
static void Main(string[] args)
{
OrderFoos();
Console.WriteLine("Press any key to end.");
Console.ReadKey();
}
private static void OrderFoos()
{
List<Foo> list = new List<Foo>();
list.Add(new Foo() { Name = "2nd", Val1 = 2, Val2 = 1, Val3 = 1 });
list.Add(new Foo() { Name = "1st", Val1 = 1, Val2 = 1, Val3 = 1 });
list.Add(new Foo() { Name = "3rd", Val1 = 1, Val2 = 2, Val3 = 1 });
list.Add(new Foo() { Name = "4th", Val1 = 2, Val2 = 1, Val3 = 2 });
list.Add(new Foo() { Name = "6th", Val1 = 4, Val2 = 1, Val3 = 3 });
list.Add(new Foo() { Name = "5th", Val1 = 3, Val2 = 1, Val3 = 3 });
list = list.OrderBy(x => x.Val3).ThenBy(x => x.Val2).ThenBy(x => x.Val1).ToList();
list.ForEach(x => Console.WriteLine(x.Name));
}
The documentation for ThenBy says
"This design enables you to specify multiple sort criteria by applying
any number of ThenBy or ThenByDescending methods."
So what you give as example code should work. In the absence of a specified comparator ThenBy uses the Default comparator. Are you sure that val1 is sortable using the default comparator?
EDIT: Doh! just saw "I can sort for any combination of two of those values just fine, but the third on is always ignored." so it seems that val1 is sortable by the default comparator.
The documentation and the answer from #Bob Horn suggests that your example should work. Can you add more details of the objects you're ordering?

Categories