Check if entity contains all components through enum flags - c#

I'm struggling a bit to understand the iteration piece here of how I would check if if the entity variable below has all of the Enum.Component entries in the variable comps. I can achieve this relatively straight-forwardly if I know there will be only one Component via a .ForEach and a basic comparison (e.g. entity.ForEach(comp => Console.WriteLine(comp.COMPONENT == Enum.Component.EXPERIENCE));), but not if I need to check for multiple components.
I'm trying to understand the nuances of C# a bit better, so I don't want to brute force this with an actual foreach (in the conventional foreach(var x in exes) type of way) or something similar, but really want to understand how I would implement this via these objects through these IEnumerable functions and working with lambda expressions. As such, I need an answer utilizing these things, unless of course this is not technically possible, though probably it is, I'm guessing.
// The Component.IComponent Interface (it's in the Component namespace)
interface IComponent {
Enum.Component COMPONENT {
get;
}
}
// The Enum.Component (it's in the Enum namespace)
enum Component {
EXPERIENCE,
HEALTH
}
// The Component.Experience (it's in the Component namespace)
class Experience : IComponent {
public ThresholdValue xp;
public int level;
public Enum.Component COMPONENT {
get {
return Enum.Component.EXPERIENCE;
}
}
}
// It probably doesn't matter, but ENTITY_MANAGER is this type
Dictionary<Guid, List<Component.IComponent>>
// Trial code beings here:
Guid GUID = new Guid();
ENTITY_MANAGER.getEntities().Add(GUID, new List<Component.IComponent> { new Component.Experience(50, 3), new Component.Health(20, 25) });
List<Component.IComponent> entity = ENTITY_MANAGER.getEntities()[new Guid()];
Enum.Component[] comps = new Enum.Component[] {
Enum.Component.EXPERIENCE,
Enum.Component.HEALTH
};
// This is where I don't know what to do and know this is wrong
comps.All(v => entity.ForEach(comp => Console.WriteLine(comp.COMPONENT == v)));

You can easily do this via Flags!
https://msdn.microsoft.com/en-us/library/system.flagsattribute(v=vs.110).aspx
First do this with your Enum:
[Flags]
enum Component {
None = 0,
EXPERIENCE = 1 << 0,
HEALTH = 1 << 1,
All = (1 << 2) - 1
}
This basically will store your values as powers of 2, with 'All' being the sum of all your flags, in this case Exp and Hp are 1 and 2, so All is 3 (1+2)
Now you can just do this in your entity class:
public Enum.Component Flags => comps.Select(c => c.Component).Distinct().Sum();
public bool HasAllFlags => Flags == Enum.Component.All;
We make our enum all distinct base 2, with all the next step -1, which means All is the sum of all your enum listings.
Then we just sum up the Enums (We might have to convert to an int first then back to the enum, I don't remember if you can just add Enums together in C#) and check if they == Component.All.
There you go!

Related

Is there a way to linking two data values, simpler than Dictionary?

I'm working on a game with Unity in which the player has some spells. I have an enum that contains all of these and I want to attach them a bool value. I think I can use a System.Collections.Generics.Dictionary with the Spells as Keys and the Boolean as Value, but is there a simpler way to do such a thing?
You can simplify Dictionary<Spell, bool> hasSpell into HashSet<Spell> (you want only Key, not Value from the initial Dictionary):
public enum Spell {
Fireball,
Levitate,
Resurrect,
};
...
HashSet<Spell> abilities = new HashSet<Spell>() {
Spell.Fireball,
Fireball.Levitate,
};
...
// If the hero can resurrect...
if (abilities.Contains(Spell.Resurrect)) {
// ...let him raises from the dead
}
Individually the simplest way of pairing two data values is to use a value tuple. This feature can be used on any Unity version from 2018.3 onwards as that's when it stopped using outdated C# versions.
var spell = ("Fireball", true);
If you'd rather be more explicit about types:
(string, bool) spell = ("Fireball", true);
(This is another approach in making things "easy")
Yes, dictionnary are simple collections but it's not really what I expect. I want something just to say "this value from the enum is true, this one is false"
This sounds you need a nice class that encapsulates the less-simple or more low-level structure (e.g. dictionary or hashset). This will things easy from the outside / API-isde.
For example:
public enum Spell
{
Firebolt,
Rage,
Flash,
};
public class SpellState
{
private HashSet<Spell> _enabled = new HashSet<Spell>();
public void EnableSpell(Spell spell)
{
_enabled.Add(spell);
}
public void DisableSpell(Spell spell)
{
_enabled.Remove(spell);
}
public bool IsSpellEnabled(Spell spell)
{
return _enabled.Contains(spell);
}
}
Usage
var spellState = new SpellState();
spellState.EnableSpell(Spell.Rage);
// later
if (spellState.IsSpellEnabled(Spell.Flash))
{
spellState.DisableSpell(Spell.Rage);
// todo
}
You could use a single bitwise value by defining enum flags, so long as you have a limited number of spells.
[Flags]
public enum Spell : long
{
Firebolt = (1 << 0),
Rage = (1 << 1),
Flash = (1 << 2),
};

How Can I Get The Value of an Item in an Array via Reflection

Skip to the third paragraph for the question.
Context: I'm creating a 2D spaceship game, and one of the game mechanics is routing power to the 7 different parts of the ship to suit the current situation you're in. There are presets that you can switch to at any time, called power configurations. I have the power configurations stored in 3 different arrays, like so:
int[] powerConfiguration1 = new int[7] {10,10,10,10,20,20,20};
int[] powerConfiguration2 = new int[7] {20,20,20,10,10,10,10};
int[] powerConfiguration3 = new int[7] {10,20,10,20,10,20,10};
When you switch configurations, it calls a method for doing so. The method makes some calculations to determine how long it will take to switch configurations. However, instead of making a switch statement and copy/pasting the code several times in the case of the player switching to any of the three configurations, I want to use PropertyInfo in System.Reflections to choose which property I need to pull values from.
Question: The problem is that I don't know how to get an item from an array. Here is what I have so far, where I'm attempting to determine how much power will need to be rerouted in total and adding it all to a variable. 0 is the index in the configuration at which I have decided to store the shield power. powerToShields is the current power being routed to the shields.
void switchConfiguration(int number) {
PropertyInfo powerConfiguration = GetType().GetProperty("powerConfiguration" + number);
int powerToReroute = 0;
powerToReroute += Mathf.Abs(powerToShields - powerConfiguration[0]);
Could someone please explain what I'm doing wrong and/or show me how to fix it? Or, is there a better way to do this?
EDIT 1: This is coded in C# (Unity).
Side thought
I guess my first question is why not store the arrays in a list. So, instead of powerConfiguration1, powerConfiguration2, powerConfiguration3, why not just store a list of int[], so
List<int[]> powerConfigurationList = new List<int[]>;
powerConfigurationList.Add(new int[7] {10,10,10,10,20,20,20});
powerConfigurationList.Add(new int[7] {20,20,20,10,10,10,10});
powerConfigurationList.Add(new int[7] {10,20,10,20,10,20,10});
That way you can get the item via:
powerToReroute = (powerConfigurationList[number])[0]
Answer to your question
However, assuming that there is some good reason that you can't, and in order to answer your exact question, do the following:
...
PropertyInfo powerConfiguration = GetType().GetProperty("powerConfiguration" + number); //this line is taken from your example above
//then you need to do something like the below
var value = (int[])powerConfiguration.GetValue(instanceThatHasTheProperty);
int powerToReroute = 0;
powerToReroute += Mathf.Abs(powerToShields - value[0]);
From your code snippet, I see you have GetType().GetProperty("powerConfiguration" + number);. I'm not sure what the actual instance is that your getting that type from. So you need to replace instanceThatHasTheProperty in my above snippet, by whatever instance you're trying to get the property's value from.
The thing that is immediately obvious to me is that the code is unnecessarily obfuscated and seems an awful lot like an X-Y problem. Using jagged arrays and reflection seems like a whole lot of work to end-around object oriented programming. My recommendation would be to create a class to store your power configurations, store multiple power configurations in a list, and then select the configuration from the list.
Sample Class for Power Configurations
public class PowerConfiguration
{
public int ID { get; set; }
public string Name { get; set; }
public int Shields { get; set; }
public int Weapons { get; set; }
public int LifeSupport { get; set; }
public int Propulsion { get; set; }
}
Inserting and Accessing your Power Configurations
public class DoStuff
{
public void LoadPowerConfiguration()
{
// Create a List to store configurations
List<PowerConfiguration> allPowerConfigurations = new List<PowerConfiguration>();
// Add some mock data to the list
allPowerConfigurations.Add(new PowerConfiguration()
{
ID = 0,
Name = "Balanced Combat",
Shields = 30,
Weapons = 30,
LifeSupport = 20,
Propulsion = 20
});
allPowerConfigurations.Add(new PowerConfiguration()
{
ID = 1,
Name = "Offensive",
Shields = 20,
Weapons = 50,
LifeSupport = 10,
Propulsion = 20
});
// Figure out which ID you what (eg. from the user pressing '0')
int selectedConfigurationID = 0;
// Get the configuration from the list
PowerConfiguration selectedConfiguration =
allPowerConfigurations.FirstOrDefault(p => p.ID == selectedConfigurationID);
// Now perform your operations against the PowerConfiguration object's properties
int powerToShields = 100;
int powerToReroute = 0;
powerToReroute += Math.Abs(powerToShields - selectedConfiguration.Shields);
}
}

Strategy for detecting (via Reflection) if Enum is of type "Flags" in C#

I'm using Reflection to read types inside an assembly (to generate code). I can see that some enumerations should have been marked with the [Flags] attribute but whoever wrote those enums forgot to add this attribute.
Is there any reliable way of detecting when an enum can be considered a "Flags" enum?
My strategy at the moment is to read the enum in descending order, and checking if the value of element(last -1) * 2 == element(last).
That works great in most cases, except when I have enums with 0, 1, and 2 values (which could be flags or not).
edit:
Example of an enum that I'd like to detect as being flags:
public enum EnumIsFlag1
{
ItemA = 2,
ItemB = 4,
ItemC = ItemA + ItemB,
ItemD = 32,
ItemE = 64,
}
edit: My question is not a duplicate... The moderator clearly didn't read my question
Clearly, this problem can only be solved heuristically but I understand that's what you are after.
Typically, flags enums have most members with a single bit set. So I would count the number of members that have only a single bit set (e.g. that are a power of two).
Then, you can devise a heuristic such as:
//Is this a flags enum?
var totalCount = ...;
var powerOfTwoCount = ...;
if (totalCount < 3) return false; //Can't decide.
if (powerOfTwoCount >= totalCount * 0.95) return true; //Looks like flags
//Probably need some cases for small values of totalCount.
The only reason multiple bits could be set in a legitimate flags enum is combinations of flags. But the number of such enum items is usually small.
This answer goes into detail about the differences between the two, and they are very minor: just some string formatting behaviour.
The strict answer to your question is that any type can be checked for the flags enum using reflection. Anything else just needs to be checked by a human. You can check for the Flags attribute directly like this;
[Flags]
enum Foo
{
A = 0,
B = 1,
C = 4
}
enum Bar
{
A = 0,
B = 1,
C = 4
}
bool IsFlagsEnum(Type t)
{
var attr = t.GetCustomAttributes(typeof(FlagsAttribute), true).FirstOrDefault();
var result = attr != null;
return result;
}
Console.WriteLine(IsFlagsEnum(typeof(Foo))); // True
Console.WriteLine(IsFlagsEnum(typeof(Bar))); // False

How to define a catch-all enum value when casting from an integer?

I've got a enum type defined in my C# code that corresponds to all possible values for the NetConnectionStatus field in Win32_NetworkAdapter WMI table, as documented here.
The documentation shows that the integers 0 through 12 each have a unique status name, but then all integers between 13 and 65,535 are lumped into one bucket called "Other." So here's my code:
[Serializable]
public enum NetConnectionStatus
{
Disconnected = 0,
Connecting = 1,
Connected = 2,
Disconnecting = 3,
HardwareNotPresent = 4,
HardwareDisabled = 5,
HardwareMalfunction = 6,
MediaDisconnected = 7,
Authenticating = 8,
AuthenticationSucceeded = 9,
AuthenticationFailed = 10,
InvalidAddress = 11,
CredentialsRequired = 12,
Other
}
This works fine for the values that are not Other. For instance, I can do this:
var result = (NetConnectionStatus) 2;
Assert.AreEqual(NetConnectionStatus.Connected, result);
But for anything in that higher numeric range, it doesn't work so great. I would like it if I could do this:
var result = (NetConnectionStatus) 20;
Assert.AreEqual(NetConnectionStatus.Other, result);
But right now that result variable gets assigned the literal value 20 instead of Other. Is there some out-of-the-box way of accomplishing this, something akin to Parse() but for integers instead of strings, or perhaps some special attribute I'm unaware of? I would prefer to not write my own wrapper method for this if there is already a good way to accomplish this.
If you have a string value, then the closest thing I can think of is to use Enum.TryParse:
NetConnectionStatus result;
if (Enum.TryParse(stringValue, out result) == false)
result = NetConnectionStatus.Other;
For an integer value that you're casting, you can use:
result = (NetConnectionStatus)integerValue;
if (Enum.GetValues(typeof(NetConnectionStatus)).Contains(result) == false)
result = NetConnectionStatus.Other;
Not really ideal, but in C# enums aren't much more than fancy names for integral values, so it's valid to stuff an integer value not in the defined values of the enums into a value of that enum type.
This solution will handle negative numbers, or cases where you have gaps in your enum values more elegantly than doing numerical comparisons.
it would be nice but no. How about
var result = (NetConnectionStatus) 20;
Assert.IsTrue(result >= (int)NetConnectionStatus.Other);
.NET does not such thing as a "any other" enumeration value bucket. Technically, enumeration (enum) is a pretty set of named constants of some underlying type (which is one of following: sbyte, short, int, long and their unsigned counterparts). You can cast an enum value to/from a corresponding type without any losses, as in this example:
enum TestEnum:int // Explicitly stating a type.
{
OnlyElement=0
}
class Program
{
static void Main(string[] args)
{
// Console.WriteLine implicitly calls ToString of the TestEnum.OnlyElement.
Console.WriteLine("OnlyElement == {0}", TestEnum.OnlyElement);
//TestEnum.OnlyElement equals to 0, as demonstrated by this casting:
Console.WriteLine("(int)OnlyElement == {0}", (int)TestEnum.OnlyElement);
//We can do it in reverse...
Console.WriteLine("(TestEnum)0 == ",(TestEnum)0);
// But what happens when we try to cast a value, which is not
// representable by any of enum's named constants,
// into value of enum in question? No exception is thrown
// whatsoever: enum variable simply holds that value, and,
// having no named constant to associate it with, simply returns
// that value when attempting to "ToString"ify it:
Console.WriteLine("(TestEnum)5 == {0}", (TestEnum)5); //prints "(TestEnum)5 == 5".
Console.ReadKey();
}
}
I'd like to repeat it again, enum in .NET is simply a value of the underlying type with some nice decorations like overriden ToString method and flags checking (look here or here if you want to know more about flags). You cannot have an integer with only 14 values like "0..12 and everything else", and so you cannot have such enum. In your example, NetConnectionStatus.Other simply receives single literal value (I assume it would most probably be '13', as the next available positive value of underlying type - however it actually depends on the compiler) as any other enumeration constant would do if not specified explicitly - and, obviously, it does not become a bucket.
However, there are options to achieve simple equation checks for integers/bytes/shorts/longs - and enums alike. Consider this extension method:
static bool IsOther(this NetConnectionStatus A)
{
return (A < (NetConnectionStatus)0) || (A > (NetConnectionStatus)12);
}
Now you can have a simple assertion like this:
var result = (NetConnectionStatus)10;
Trace.Assert(result.IsOther()); //No assertion is triggered; result is NetConnectionStatus.AuthenticationFailed
and
var result = (NetConnectionStatus)20;
Trace.Assert(result.IsOther()); //Assertion failed; result is undefined!
(Of course you can replace IsOther method with IsNotOther, overload it and pretty much anything else you could do with a method.)
Now there is one more thing. Enum class itself contains a method called IsDefined, which allows you to avoid checks for specific enum's value boundaries (<0, >12), therefore preventing unwanted bugs in case enum values would ever be added/removed, at the small performance cost of unboxing and checking each value in enum for a match (I'm not sure how this works under the hood though, I hope these checks are optimized). So your method would look like this:
static bool IsOther(NetConnectionStatus A)
{
return !Enum.IsDefined(typeof(NetConnectionStatus), A);
}
(However, concluding from enum's name, it seems like you want to make a network application/server, and for these performance might be of very great importance - but most probably I'm just being paranoid and this will not be your application's bottleneck. Stability is much more of concern, and, unless you experience real troubles with performance, it is considered to be much better practice to enable as much stability&safety&portability as possible. Enum.IsDefined is much more understandable, portable and stable than the explicit boundaries checking.)
Hope that helps!
Thanks everyone for the replies. As confirmed by all of you, there is indeed no way to do this out-of-the-box. For the benefit of others I thought I'd post the (custom) code I ended up writing. I wrote an extension method that utilizes a custom attribute on the enum value that I called [CatchAll].
public class CatchAll : Attribute { }
public static class EnumExtensions
{
public static T ToEnum<T, U>(this U value) where T : struct, IConvertible where U : struct, IComparable, IConvertible, IFormattable, IComparable<U>, IEquatable<U>
{
var result = (T)Enum.ToObject(typeof(T), value);
var values = Enum.GetValues(typeof(T)).Cast<T>().ToList();
if (!values.Contains(result))
{
foreach (var enumVal in from enumVal in values
let info = typeof(T).GetField(enumVal.ToString())
let attrs = info.GetCustomAttributes(typeof(CatchAll), false)
where attrs.Length == 1
select enumVal)
{
result = enumVal;
break;
}
}
return result;
}
}
So then I just have to apply that [CatchAll] attribute to the Other value in the enum definition. Then I can do things like this:
int value = 13;
var result = value.ToEnum<NetConnectionStatus, int>();
Assert.AreEqual(NetConnectionStatus.Other, result);
And this:
ushort value = 20;
result = value.ToEnum<NetConnectionStatus, ushort>();
Assert.AreEqual(NetConnectionStatus.Other, result);

Design level problem: multiple enums or looping the enum in UI code in order to make visibility decision?

we have a debate about a BEST PRACTISE from a .NET architecture DESIGN POINT OF VIEW:
Task: How to manage role based visibility in UI with enum?
For example: I want to show all team types [a,b,c,d,e] to administrator but only team types [a,b,c] to normal user.
First I have enum which includes all team types:
public enum TeamType { a, b, c, d, e }
I use it like this:
if (IsAdminitrator())
comboboxTeamtypes.Items.AddRange(Enum.GetNames(typeof(TeamType)));
Now I should decide how to implement else clause. Because enums can't be inherited I have two alternative approaches:
1) Should I introduce an other role specific enum:
public enum TeamTypeOthers {a, b, c }
and then I would have:
else
comboboxTeamtypes.Items.AddRange(Enum.GetNames(typeof(TeamTypeOthers)));
2) Or should I forget creating any role specific enum TeamTypeOthers and just loop the original TeamType enum values in UI-code:
else
{
foreach (TeamType teamtype in Enum.GetValues(typeof(TeamType)))
{
if (asdf == TeamType.a)
comboboxTeamtypes.Items.Add(teamtype);
else if (asdf == TeamType.b)
comboboxTeamtypes.Items.Add(teamtype);
if (asdf == TeamType.c)
comboboxTeamtypes.Items.Add(teamtype);
}
}
I think the first solution is nice and clean (though repetitive which is not so nice). But now I also make decision about the use of enum in deeper architecture than in solution 2 which is probably bad and supports the use of solution 2. To me solution 2 is ugly and messy because I don't like loop cultivation around the code.
I would change things a little and use simple bitmasking for permissions:
public enum TeamType
{
a = 1, // or 00001
b = 2, // or 00010
c = 4, // or 00100
d = 8, // or 01000
e = 16 // or 10000
}
Then each usertype gets its permission level set (each available permission added together):
int administratorLevel = 32; // 11111
int userLevel = 7; // 00111
And then the bitmasking comes in when you populate your dropdown in the UI:
comboboxTeamTypes.Items.AddRange(
Enum.GetValues(typeof(TeamType))
.Where(v => myLevel & v == v)
.Select(v => Enum.GetName(typeof(TeamType), v));
What is your programming language? In Java, I would tell you to create enum class like below, but obviously this isn't Java.
public enum TeamType {
A(false), B(false), C(false), D(true), E(true);
private final boolean isAdmin;
public TeamType(boolean isAdmin) {
this.isAdmin = isAdmin;
}
public boolean isAdmin() {
return this.isAdmin;
}
}

Categories