【问题标题】:Faster way to compare enums?比较枚举的更快方法?
【发布时间】:2019-09-18 08:59:35
【问题描述】:

我正在寻找一种更好的方法来比较枚举。目前,我有一个具有 3 个不同可能值的枚举:

public enum Elements { fire, water, earth };

但是,当两个元素碰撞时发生某些事情的函数示例:

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...}
}

那只适用于火系!

我已经搜索了一段时间,并查看了类似的 SO 问题,但我不确定如何制定问题。我发现的只是诸如“'==' 或 '.Equals()' 比较 Enums 更快吗???”之类的问题,这是完全不同的。

有没有简单的方法来做到这一点?我已经在单独的 Manager 中处理了这些情况,但这仍然让我很恼火。

编辑: 元素的组合总是具有相同的结果。所以火 + 水 = X,水 + 火 = X。

【问题讨论】:

  • 你能详细说明你想要做什么吗?我的意思是,element1element2 是什么?它们是如何关联的,是否有element3(正如你所说的“我有 3 个”......你的意思是 3 个枚举值还是 3 个变量)。请添加一些上下文。也许这是一个 xy 问题,并且有不同的方法。
  • Dictionary<Elements , Dictionary<Elements, Action<..>> actions ?然后actions[element1][element2](...)(当然要先设置)
  • 我已经详细阐述了这个概念。认为这已经足够清楚了,但如果您认为我应该解释更多,请询问。
  • 嵌套switch 语句。
  • fire+waterwater+fire 有不同的结果吗?

标签: c# enums compare


【解决方案1】:

C# 7.0 中引入C# switch conditions 将是更简洁的代码。

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;
    }
}

更新:element1element2 的顺序无关紧要。也忽略相等的元素。

【讨论】:

    【解决方案2】:

    一个选项是拥有一个可以调用的操作字典。例如:

    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");
        }
    }
    

    要使用它,很简单:

    var elementActionFactory = new ElementActionFactory();
    
    var element1 = Elements.Fire;
    var element2 = Elements.Water;
    
    elementActionFactory.Invoke(element1, element2);
    

    【讨论】:

      【解决方案3】:

      假设元素组合的顺序无关紧要,您可以将枚举视为一个位字段,即一组标志 - 这样您就可以将它们组合起来,从而获得一个简单的switch。例如:

      [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;
          }
      }
      

      【讨论】:

      • 请注意,Flags 属性在这里实际上并没有做任何事情,事实上,它几乎什么都不做。
      • @DavidG,这是一个公平的评论,我已经重新措辞以减少对它的重视。
      【解决方案4】:

      对于更简洁的代码,我建议使用复杂的开关...

      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;
              }
      

      【讨论】:

      • 我不推荐这种方法。假设您添加了另一个元素(例如air),然后您将开关中的代码量加倍,这使得它非常难以阅读。
      【解决方案5】:

      使用元组,您可以避免嵌套 if:

      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
      }
      

      如果你创建一个单独的函数,你可以更简化它:

      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));
       }
      

      【讨论】:

        猜你喜欢
        • 2011-10-16
        • 2012-05-04
        • 1970-01-01
        • 2023-03-09
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-15
        相关资源
        最近更新 更多