【问题标题】:is there any way to simplify this double conditional clauses structure?有什么办法可以简化这种双条件从句结构?
【发布时间】:2012-03-28 09:55:10
【问题描述】:

例如

if (x=="A)
    switch (y)
    {
    case "1": Do1();break;
    case "2": Do2();break;
    case "3": Do3();break;
    }
else if (x=="B")
    switch (y)
    {
    case "1": Do4();break;
    case "2": Do5();break;
    case "3": Do6();break;
    }
else
    switch (y)
    {
    case "1": Do7();break;
    case "2": Do8();break;
    case "3": Do9();break;
    }

我希望我可以执行以下操作,但是它有许多冗余检查。

    if (x=="A" && y=="1")
        Do1();
    else if (x=="A" && y=="2")
        Do2();
    else if (x=="A" && y=="3")
        Do3();
    else if (x=="B" && y=="1")
        Do4();
    else if (x=="B" && y=="2")
        Do5();
    else if (x=="B" && y=="3")
        Do6();
    else if (x=="C" && y=="1")
        Do7();
    else if (x=="C" && y=="2")
        Do8();
    else if (x=="C" && y=="3")
        Do9();

【问题讨论】:

  • 2 个字:决策树。您可能可以使用映射到代表的字典字典。
  • 另一种选择是将 X 和 Y 连接成一个字符串。作为单级开关可能更容易阅读。
  • 您是否发现自己在整个代码中进行了大量此类检查?如果是这样,这可能是将 OOP 引入您的项目的好时机。
  • 能否将“1”、“2”、“3”作为参数传递给目标方法,例如DoA(1)、DoA(2)、DoA(3)?
  • @Tung 我之前试过,结果一团糟stackoverflow.com/questions/9892660/…

标签: c#


【解决方案1】:

引入 OOPS 的建议真的很棒,请不要忽略该评论。暂时你可以这样写代码。

var combinedText = x+y;
    switch(combinedText)
    {
        case "A1": Do1(); break;
        case "A2": Do2(); break;
        case "A3": Do3(); break;
        case "B1": Do4(); break;
        case "B2": Do5(); break;
        case "B3": Do6(); break;
        case "C1": Do7(); break;
        case "C2": Do8(); break;
        case "C3": Do9(); break;
    }

【讨论】:

【解决方案2】:

您的代码目前有两个职责 - 确定要执行的方法集(变量 x)和确定要执行的确切方法(变量 y)。使代码更清晰的最简单选项 - 拆分此职责并提取方法,这将决定从一组方法中调用哪个方法

switch (x)
{
    case "A": DoA(y); break;
    case "B": DoB(y); break;
    default:
        DoDefault(y); break;
}

现在您的调用者代码很简单。这是 DoX 方法之一:

private void DoA(string y)
{
    switch (y)
    {
        case "1": Do1(); break;
        case "2": Do2(); break;
        case "3": Do3(); break;
    }
}

其他选项是让 .net 通过使用多态性来决定调用哪组方法。但是在您只有一个 switch(x) 块的简单情况下,我不建议这样做。如果您的实际代码更复杂,则考虑提取将包含一组功能(Do1、Do2、Do3)并决定该功能执行的类。例如。调用代码:

IDo ido = CreateIDo(x);
ido.Do(y);

是的,仅此而已。非常干净。下面是IDo接口创建代码:

public static IDo CreateIDo(string x)
{
    switch (x)
    {
        case "A": return new A();
        case "B": return new B();
        default:
            return new C();
    }
}

这里是 A 类,它封装了第一组方法和执行时的决策:

public interface IDo
{
    void Do(string y);
}

public class A : IDo
{
    public void Do(string y)
    {
        switch (y)
        {
            case "1": Do1(); break;
            case "2": Do2(); break;
            case "3": Do3(); break;
        }
    }

    private void Do1() { }
    private void Do2() { }
    private void Do3() { }
}

同样,如果您的实际代码更复杂,请使用它。

【讨论】:

    【解决方案3】:

    我会使用元组的 IEnumerable 集合和 Action delegate 来定义要调用的方法列表,将列表创建为私有字段或在类初始化程序中,或者为了灵活,您可以将元组添加到公共财产根据需要。如果您需要传入参数,请使用 Action 委托的重载版本之一,即:Action(t1, t2) 等。

    如果您需要返回值,请按照其他答案使用Func delegate

            IEnumerable<Tuple<string, string, Action>> actions = new List<Tuple<string, string, Action>>() { 
            Tuple.Create<string, string, Action>("A", "1", SomeMethod1), 
            Tuple.Create<string, string, Action>("A", "2", SomeMethod2) 
            };
    
            string x = "A";
            string y = "2";
    
            var action = actions.FirstOrDefault(t => ((t.Item1 == x) && (t.Item2 == y)));
    
            if (action != null)
                action.Item3();
            else
                DoSomeDefaultMethod();
    
    
            public void SomeMethod1() { // Whatever you want to do  }
            public void SomeMethod2() { // Whatever you want to do  }
    
            public void DoSomeDefaultMethod() { // Default Method  } 
    

    【讨论】:

      【解决方案4】:
      void Main()
      {
          Dictionary<string, Action> d = new Dictionary<string, Action>()
          {
              {"A1", Do1},
              {"A2", Do2},
              {"A3", Do3},
              {"B1", Do4},
              {"B2", Do5},
              {"B3", Do6},
              {"1", Do7},
              {"2", Do8},
              {"3", Do9}
          };
          var x = "A";
          var y = "1";
          var action = x == "A" || x == "B" ? x + y : y;
          if (d.ContainsKey(action))
              d[action]();
      }
      
      public void Do1() {}
      public void Do2() {}
      public void Do3() {}
      public void Do4() {}
      public void Do5() {}
      public void Do6() {}
      public void Do7() {}
      public void Do8() {}
      public void Do9() {}
      

      编辑

      我记得fluent functional switch:

      var sw = new Switch<string>(action)
                          .Case("A1", s => Do1())
                          .Case("A2", s => Do2());
      

      【讨论】:

      • @Lloyd,没有理由.. LINQfy 它:P。 Downvoter,很高兴改进答案,你能解释一下哪个方向吗?
      • 我刚刚询问了 Linq,因为它更干净一些,您的回答不会被否决。
      • @Lloyd,我知道。我根本没想过要添加 LINQ,所以我没有充分的理由不添加它..
      【解决方案5】:

      如果您不想更改当前结构的大部分内容(并且不想创建新类型等),请考虑这一点

      将它们添加到如下所示的元组中

      var tuples = new List<Tuple<string,string,Func<>>()>(); // Func should be of your Do() type
      

      将带有相关函数的条件数据添加到列表中

      tuples.Add(new Tuple<string,string,Func<>>("A","1", Do1()));
      ...
      

      在需要时直接使用条件调用它

      var function = tuples.Where(x => x.item1 == "A" && x.item2 == "1").Select(x => x.item3);
      function.Invoke(); // to call it.
      

      现在,如果您将来有更多条件,您可以将它们添加到列表中而无需更改任何代码。

      【讨论】:

        【解决方案6】:

        使用类似的东西。只有三个如果会做。

        if (x == "A")
        {
         int a = (y == "1") ? do1() : ((y == "2") ? do2() : do3());
        }
        }
            int do1() { return 10; }
            int do2() { return 10; }
            int do3() { return 10; }
        

        【讨论】:

          【解决方案7】:

          我猜你的代码中不止一个地方执行了 X 上的同一种开关,如果是这样,请重构它并使用 polymorphism instead

          如果 X 是字符串优先 replace the typecode with class 并使用多态性。

          【讨论】:

          • 如何解决这个问题?创造9+1种?
          • 不是9+1而是3+3型
          • 那么如果是 3 + 3 是不是更好?
          • 当然,如果同一种开关用的地方太多,就需要自己创建了。不然怎么维护?
          • 我之前尝试过多态,但效果不佳stackoverflow.com/questions/9892660/…
          猜你喜欢
          • 2015-08-26
          • 1970-01-01
          • 2019-02-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-12
          相关资源
          最近更新 更多