Enum.HasFlag is not working as expected [duplicate] - c#

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
}

Related

How to extract a specific value from the linq query?

I am building a NET 5 API and am unable to extract and calculate something. I have a table StockTransaction which among other has property Quantity (I skipped some properties for brevity):
public class StockTransaction : BaseEntity
{
public int Id { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
public bool Purchase { get; set; }
public int Resolved { get; set; }
}
Suppose I have 7 transactions, all of which are purchase:
List<StockTransaction> list = new List<StockTransaction>
{
new StockTransaction {Id = 1, Purchase = true, Quantity = 10, Resolved = 5, Price = 50},
new StockTransaction {Id = 2, Purchase = true, Quantity = 5, Resolved = 5, Price = 70},
new StockTransaction {Id = 3, Purchase = true, Quantity = 8, Resolved = 8, Price = 25},
new StockTransaction {Id = 4, Purchase = true, Quantity = 7, Resolved = 5, Price = 77},
new StockTransaction {Id = 5, Purchase = true, Quantity = 1, Resolved = 1, Price = 23},
new StockTransaction {Id = 6, Purchase = true, Quantity = 3, Resolved = 0, Price = 14},
new StockTransaction {Id = 7, Purchase = true, Quantity = 2, Resolved = 0, Price = 17},
};
And I would like to get the value of the last 7 quantities, which in this case gives 176 ((2 x 17) + (3 x 14) + (1 x 23) + (1 x 77)). (How) can this be done? Every help and hint is more then appreciated...
You can use
var last3=list.OrderByDescending(x=>x.CreatedDate).Take(3).Select(x=>x.Quantity * x.Price).Sum();
var requiredSum=last3+list.Where(x=>x.id==4).Select(x=>x.Price).FirstOrDefault();
Although you have tagged your question with LINQ, do it with a normal loop:
private static decimal SumOfLastTransaction(IEnumerable<StockTransaction> stockTransactions, int max)
{
decimal result = 0;
int sum = 0;
foreach(var stockTransaction in stockTransactions.OrderByDescending(x => x.Id))
{
if(sum + stockTransaction.Quantity <= max)
{
result += stockTransaction.Quantity * stockTransaction.Price;
sum += stockTransaction.Quantity;
}
else
{
result += (max - sum) * stockTransaction.Price;
return result;
}
}
return result;
}
You loop over the last items in your list. You sum the amount of transactions and check whether it is smaller than your maximum. As long as they are smaller, you can add the amount of transactions. If not, you check how much is missing until your maximum is reached and substract this from your quantity.
Online demo: https://dotnetfiddle.net/9oM4pj

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
}

where is the enum declared from user input c#

I have two enums and I want to determine from user input(string), in which array is the enum with the same name from user input
public enum LengthUnit
{
mm = -3,
cm = -2,
dm = -1,
m = 0,
km = 3
}
public enum NumericUnit
{
b = 2,
o = 8,
d = 10,
h = 16
}
string input = "cm";
Sounds like you want Enum.TryParse which will let you pass a string and the enum type as parameters and an out parameter as the result if the TryParse succeeds.

Get values of an enum variable having duplicate values with different keys

I've an Enum for 52 playing cards, as mentioned below,
public enum Card
{
AceClubs = 11,
AceDiamonds = 11,
AceHearts = 11,
AceSpades = 11,
DeuceClubs = 2,
DeuceDiamonds = 2,
DeuceHearts = 2,
DeuceSpades = 2,
EightClubs = 8,
EightDiamonds = 8,
EightHearts = 8,
EightSpades = 8,
FiveClubs = 5,
FiveDiamonds = 5,
FiveHearts = 5,
FiveSpades = 5,
FourClubs = 4,
FourDiamonds = 4,
FourHearts = 4,
FourSpades = 4,
JackClubs = 11,
JackDiamonds = 11,
JackHearts = 11,
JackSpades = 11,
KingClubs = 13,
KingDiamonds = 13,
KingHearts = 13,
KingSpades = 13,
NineClubs = 9,
NineDiamonds = 9,
NineHearts = 9,
NineSpades = 9,
QueenClubs = 12,
QueenDiamonds = 12,
QueenHearts = 12,
QueenSpades = 12,
SevenClubs = 7,
SevenDiamonds = 7,
SevenHearts = 7,
SevenSpades = 7,
SixClubs = 6,
SixDiamonds = 6,
SixHearts = 6,
SixSpades = 6,
TenClubs = 10,
TenDiamonds = 10,
TenHearts = 10,
TenSpades = 10,
ThreeClubs = 3,
ThreeDiamonds = 3,
ThreeHearts = 3,
ThreeSpades = 3
}
I want to create a list from enum
var cards = Enum.GetValues(typeof(Card));
but it returns duplicate keys in list.
use Enum.GetNames instead of Enum.GetValues
I suggested using two enums for suit and value:
public enum CardSuit {
Clubs = 1,
Diamonds = 2,
Hearts = 3,
Spades = 4,
};
public enum CardValue {
Ace = 1,
Deuce = 2,
...
King = 13,
};
then implement an extension method to get actual card value (since both Jack and Ace corresponds to 11):
public static class ValueExtensions() {
public static int ActualValue(this CardValue value) {
if (value == CardValue.Ace)
return 11; // Ace is 11
else
return (int) value;
}
}
Finally
public class Card {
public Card (CardSuit suit, CardValue value) {
Suit = suit;
Value = value;
}
public CardSuit Suit {get; private set;}
public CardValue Value {get; private set;}
}
...
Card[] pack = Enum
.GetValues(typeof(CardSuit))
.OfType<CardSuit>()
.SelectMany(suit => Enum
.GetValues(typeof(CardValue))
.OfType<CardValue>()
.Select(value => new Card(suit, value)))
.ToArray();
//TODO: Shuffle the pack here
Card[] hand = pack.Take(5).ToArray();
int handValue = hand.Sum(card => card.Value.ActualValue());
Your mistake is to use the same value for different things. Enums are not intended to have duplicate values (unless they mean the same thing).
When the program is running, enums are held as integers - not names.
The debugger then takes an integer from the program (4) and displays it as the first enum it can find (FourClubs). This is just for your convenience when debugging - the program still uses the integer (4).
You can remove the duplicates from the array using Linq:
var uniqueCards = cards.Distinct().ToArray();

using linq query to find value that differs from previously found value

Say i have a class that contains these items publicly accessible via properties:
class MyClass
{
int switch1; //0 or 1
int switch2; //0 or 1
int switch3; //0 or 1
}
This class represents switch states, and each time a switch state changes, i would like to add it to my transition list
I have a large sorted list that contains instances of this class and would like to use a query to capture only the entries in my list where the switch state for any switch changes.
Is this possible using a linq query?
try this:
Assuming your class looks like:
public class State
{
public int Id { get; set; }
public int Switch1 { get; set; }
public int Switch2 { get; set; }
public int Switch3 { get; set; }
public override bool Equals(object obj)
{
var other = obj as State;
if (other != null)
{
return Switch1 == other.Switch1 &&
Switch2 == other.Switch2 &&
Switch3 == other.Switch3;
}
return false;
}
}
I just added an Equals() to compare flags and my Id field is purely to demonstrate which items changed.
We can then craft a LINQ query like:
State previous = null;
var transitions = list.Where(s =>
{
bool result = !s.Equals(previous);
previous = s;
return result;
})
.ToList();
Not elegant, but it works, if you had this data set:
var list = new List<State>
{
new State { Id = 0, Switch1 = 0, Switch2 = 0, Switch3 = 0 },
new State { Id = 1, Switch1 = 0, Switch2 = 0, Switch3 = 0 },
new State { Id = 2, Switch1 = 1, Switch2 = 0, Switch3 = 0 },
new State { Id = 3, Switch1 = 0, Switch2 = 1, Switch3 = 0 },
new State { Id = 4, Switch1 = 0, Switch2 = 1, Switch3 = 0 },
new State { Id = 5, Switch1 = 0, Switch2 = 1, Switch3 = 0 },
new State { Id = 6, Switch1 = 1, Switch2 = 1, Switch3 = 0 },
new State { Id = 7, Switch1 = 0, Switch2 = 0, Switch3 = 1 },
new State { Id = 8, Switch1 = 0, Switch2 = 0, Switch3 = 1 },
new State { Id = 9, Switch1 = 0, Switch2 = 0, Switch3 = 0 },
};
And ran the query, the list would contain your state transitions at items: 0, 2, 3, 6, 7, 9
I would do as follow:
class MyClass
{
int ID; //needs for recognize the message
int switch1; //0 or 1
int switch2; //0 or 1
int switch3; //0 or 1
public int Pattern
{
get { return switch1 + switch2 << 1 + switch3 << 2; }
}
}
Then it must be declared a dictionary with the previous-state messages:
Dictionary<int, int> _prevStates;
each cell has for key the ID, and for value the "Pattern" of the message.
At this point, let's suppose that the new incoming message stream is a list of MyClass:
IEnumerable<MyClass> incoming = ...
var changed = from msg in incoming
where _prevStates.ContainsKey(msg.ID) //what to do?
where _prevStates[msg.ID].Pattern != msg.Pattern
select msg;
Finally, you must update the dictionary with the changed patterns.
Cheers

Categories