JasperMW
JasperMW

Reputation: 533

Faster way to compare enums?

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

Answers (5)

steve16351
steve16351

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

Frode Evensen
Frode Evensen

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

DavidG
DavidG

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

SomeBody
SomeBody

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

OMR
OMR

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

Related Questions