Reputation: 533
I'm looking for a better way to compare enums. Currently, I have an enum with 3 different possible values:
public enum Elements { fire, water, earth };
However, an example of a function where something happens when two Elements collide:
Public Void ElementCollisionExample(Elements element1, Elements element2){
if (element1 == Elements.fire){
if (element2 == Elements.fire){
//Do stuff
} else if (element2 == Elements.water){
// Do stuff
} else {
// Do stuff
}
} else if (element2 == Elements.water){...etc...}
}
And that is only for the Fire Element!
I've searched a while, and looked on similar SO questions, but I'm not sure how to formulate the problem. All I've found are questions such as "Is '==' or '.Equals()' faster to compare Enums???", which is entirely different.
Is there an easy way to do this? I already have these conditions being handled in a separate Manager, but it still irritates me.
EDIT: A combination of elements always has the same outcome. So Fire + Water = X, and Water + Fire = X as well.
Upvotes: 0
Views: 168
Reputation: 5812
Assuming that the order in which the elements are combined does not matter, you could treat the enumeration as a bit field, that is, a set of flags - so you can combine them allowing you to have a simple switch
. For example:
[Flags]
public enum Elements
{
none = 0b0000_0000_0000,
fire = 0b0000_0000_0001,
water = 0b0000_0000_0010,
earth = 0b0000_0000_0100
};
public void ElementCollisionExample(Elements element1, Elements element2)
{
switch (element1 | element2)
{
case Elements.fire | Elements.water:
Console.WriteLine("The fire is extinguished");
break;
case Elements.earth | Elements.fire:
Console.WriteLine("The earth goes black");
break;
}
}
Upvotes: 2
Reputation: 613
It will be cleaner code with C# switch conditions introduced in C# 7.0.
public void ElementCollisionExample(Elements element1, Elements element2)
{
// Do nothing on equal elements
if (element1 == element2) return;
switch (element1)
{
case Elements.fire when element2 == Elements.water:
case Elements.water when element2 == Elements.fire:
// Do stuff
break;
case Elements.fire when element2 == Elements.earth:
case Elements.earth when element2 == Elements.fire:
// Do stuff
break;
case Elements.water when element2 == Elements.earth:
case Elements.earth when element2 == Elements.water:
// Do stuff
break;
}
}
Updated: Order of element1
and element2
does not matter. Also ignoring equal elements.
Upvotes: 2
Reputation: 118937
One option is to have a dictionary of actions you can invoke. For example:
public class ElementActionFactory
{
// Somewhere to keep our actions, using tuple to pair up elements
private Dictionary<(Elements, Elements), Action> _elementActions;
public ElementActionFactory()
{
// Initialise the action dictionary
_elementActions = new Dictionary<(Elements, Elements), Action>
{
{(Elements.Fire, Elements.Fire), FireAndFire},
{(Elements.Fire, Elements.Water), FireAndWater},
{(Elements.Fire, Elements.Earth), FireAndEarth},
// etc.
};
}
public void Invoke(Elements element1, Elements element2)
{
// Try to get the action, and if we don't find it...
if (!_elementActions.TryGetValue((element1, element2), out var action))
{
// reverse the arguments and try again - this assumes the order is not important
if (!_elementActions.TryGetValue((element2, element1), out action))
{
return; //No action was found
}
}
// Actually run the method now
action.Invoke();
}
public void FireAndFire()
{
Console.WriteLine("Fire And Fire");
}
public void FireAndWater()
{
Console.WriteLine("Fire And Water");
}
public void FireAndEarth()
{
Console.WriteLine("Fire And Earth");
}
}
And to use it, it's simply:
var elementActionFactory = new ElementActionFactory();
var element1 = Elements.Fire;
var element2 = Elements.Water;
elementActionFactory.Invoke(element1, element2);
Upvotes: 2
Reputation: 8743
With tuples, you can avoid the nested ifs:
public void ElementCollisionExample(Elements element1, Elements element2)
{
Tuple<Elements,Elements> elements = Tuple.Create(element1,element2);
if(elements.Equals(Tuple.Create(Elements.fire, Elements.earth))
{
//do something
}
else if(elements.Equals(Tuple.Create(Elements.fire, Elements.water))
{
// do something
}
// and so on
}
You can simplify it more if you create a separate function:
public void ElementCollisionExample(Elements element1, Elements element2)
{
Tuple<Elements,Elements> elements = Tuple.Create(element1,element2);
if(CompareElements(elements, Elements.fire, Elements.earth))
{
//do something
}
else if(CompareElements(elements, Elements.fire, Elements.water))
{
// do something
}
// and so on
}
private bool CompareElements(Tuple<Elements,Elements> actual, Elements expected1, Elements expected2)
{
return actual.Equals(Tuple.Create(expected1, expected2));
}
Upvotes: 0
Reputation: 12188
For Cleaner Code i suggest using complex switch ...
Elements x, y;
switch (x)
{
case Elements.fire:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
case Elements.water:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
case Elements.earth:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
}
Upvotes: 0