C# 动态表达式中的代码气味

C# 动态表达式中的代码气味,c#,refactoring,C#,Refactoring,这段代码解决了中概述的一个有趣的难题 问题:这里似乎有很多重复。。这里突然想到了“干燥”(不要重复)原则。有人看到重构吗 string opZ = ""; string opA = ""; string opB = ""; string opC = ""; string opD = ""; for (int h = 1; h <= 2; h++) // making the first numb

这段代码解决了中概述的一个有趣的难题

问题:这里似乎有很多重复。。这里突然想到了“干燥”(不要重复)原则。有人看到重构吗

        string opZ = "";
        string opA = "";
        string opB = "";
        string opC = "";
        string opD = "";
        for (int h = 1; h <= 2; h++) // making the first number positive or negative
        {
            if (h == 1) opZ = "";
            if (h == 2) opZ = "-";

            for (int i = 1; i <= 4; i++)
            {
                if (i == 1) opA = "*";
                if (i == 2) opA = "/";
                if (i == 3) opA = "+";
                if (i == 4) opA = "-";
                for (int j = 1; j <= 4; j++)
                {
                    if (j == 1) opB = "*";
                    if (j == 2) opB = "/";
                    if (j == 3) opB = "+";
                    if (j == 4) opB = "-";
                    for (int k = 1; k <= 4; k++)
                    {
                        if (k == 1) opC = "*";
                        if (k == 2) opC = "/";
                        if (k == 3) opC = "+";
                        if (k == 4) opC = "-";
                        for (int l = 1; l <= 4; l++)
                        {
                            if (l == 1) opD = "*";
                            if (l == 2) opD = "/";
                            if (l == 3) opD = "+";
                            if (l == 4) opD = "-";
                            string expression = opZ + 1 + opA + 3 + opB + 5 + opC + 7 + opD + 9;
                            DataTable dummy = new DataTable();
                            double result = Convert.ToDouble(dummy.Compute(expression, string.Empty));
                            if (result == 3)
                                Debug.WriteLine(expression + " = 3");

                            if (result == 47)
                                Debug.WriteLine(expression + " = 47");

                            if (result == 18)
                                Debug.WriteLine(expression + " = 18");

                        }
                    }
                }
            }
        }
string opZ=”“;
字符串opA=“”;
字符串opB=“”;
字符串opC=“”;
字符串opD=“”;

对于(inth=1;h那么,第一个明显的重构将是使用一组运算符:

String[] operators = { null, "*", "/", "+", "-" };
然后使用:

opC = operators[j]; // etc
(就我个人而言,我会使用从0到3的循环,而不是从1到4的循环——这在我看来更为惯用,但这是另一回事。)

然后是构建排列的方法。我实际上会使用LINQ来实现这一点:

string[] prefixes = { "", "-" };
string[] operators = { "*", "/", "+", "-" };
var expressions = from prefix in prefixes
                  from opA in operators
                  from opB in operators
                  from opC in operators
                  from opD in operators
                  select prefix + 1 + opA + 3 + opB + 5 + opC + 7 + opD + 9;

foreach (string expression in expressions)
{
    ...
}

第一个明显的重构是使用一系列操作符:

String[] operators = { null, "*", "/", "+", "-" };
然后使用:

opC = operators[j]; // etc
(就我个人而言,我会使用从0到3的循环,而不是从1到4的循环——这在我看来更为惯用,但这是另一回事。)

然后是构建排列的方法。我实际上会使用LINQ来实现这一点:

string[] prefixes = { "", "-" };
string[] operators = { "*", "/", "+", "-" };
var expressions = from prefix in prefixes
                  from opA in operators
                  from opB in operators
                  from opC in operators
                  from opD in operators
                  select prefix + 1 + opA + 3 + opB + 5 + opC + 7 + opD + 9;

foreach (string expression in expressions)
{
    ...
}

我认为使用
DataTable.Compute
时这样做没有实际意义,但是

var calculator = new DataTable () ;
var operators  = "*/+-" ;
for (int i = 0 ; i < 0x200 ; ++i)
{
  var value = calculator.Compute (String.Format ("{0}1{1}3{2}5{3}7{4}9",
    (i & 0x100) != 0 ? "-" : "",
    operators[(i >> 0) & 3],
    operators[(i >> 2) & 3],
    operators[(i >> 4) & 3],
    operators[(i >> 6) & 3]), String.Empty) ;
  ...
}
var计算器=新数据表();
var运算符=“*/+-”;
对于(int i=0;i<0x200;++i)
{
var value=calculator.Compute(String.Format(“{0}1{1}3{2}5{3}7{4}9”),
(i&0x100)!=0?”-“:”,
运算符[(i>>0)和3],
运算符[(i>>2)和3],
运算符[(i>>4)和3],
运算符[(i>>6)和3]),String.Empty);
...
}
否则,如果更深奥一些,这肯定会更快:

var opstrings = "+-*/" ;
var operators = new Func<int, int, int>[] {
  (a, b) => a + b,
  (a, b) => a - b,
  (a, b) => a * b,
  (a, b) => a / b, } ;
for (int i = 0 ; i < 0x200 ; ++i)
{
  var stack = 0 ; // seed value
  var last  = 0 ; // imitate + for lowest precedence
  var value =(i & 0x100) != 0 ? -1 : 1 ;

  for (int j = 0 ; j < 5 ; ++j)    // extra item to force last reduction
  {
    var oper  = (i >> j * 2) & 3 ; // "input" operator
    var input =  3  + j * 2 ;      // "input" number
    if (oper / 2 <= last / 2)      // reduce below top?
    {
      stack = operators[last] (stack, value) ;
      last  = oper  ;              // shift operator
      value = input ;              // shift number
    }
    else                           // reduce top
      value = operators[oper] (value, input) ;
  }

  var result  = stack ;
  if (result == 3 || result == 47 || result == 18)
    Debug.WriteLine ("{0}1{1}3{2}5{3}7{4}9 = {5}",
      (i & 0x100) != 0 ? "-" : "",
      opstrings[(i >> 0) & 3],
      opstrings[(i >> 2) & 3],
      opstrings[(i >> 4) & 3],
      opstrings[(i >> 6) & 3],
      result) ;
}
var opstrings=“+-*/”;
变量运算符=新函数[]{
(a,b)=>a+b,
(a,b)=>a-b,
(a,b)=>a*b,
(a,b)=>a/b,};
对于(int i=0;i<0x200;++i)
{
var stack=0;//种子值
var last=0;//模仿+表示最低优先级
var值=(i&0x100)!=0?-1:1;
对于(int j=0;j<5;++j)//强制最后一次缩减的额外项
{
var oper=(i>>j*2)&3;/“输入”运算符
var输入=3+j*2;/“输入”编号
如果(操作/2>0)&3],
opstrings[(i>>2)和3],
opstrings[(i>>4)和3],
opstrings[(i>>6)和3],
结果);
}

我想在使用
DataTable.Compute时这样做没有实际意义,但是

var calculator = new DataTable () ;
var operators  = "*/+-" ;
for (int i = 0 ; i < 0x200 ; ++i)
{
  var value = calculator.Compute (String.Format ("{0}1{1}3{2}5{3}7{4}9",
    (i & 0x100) != 0 ? "-" : "",
    operators[(i >> 0) & 3],
    operators[(i >> 2) & 3],
    operators[(i >> 4) & 3],
    operators[(i >> 6) & 3]), String.Empty) ;
  ...
}
var计算器=新数据表();
var运算符=“*/+-”;
对于(int i=0;i<0x200;++i)
{
var value=calculator.Compute(String.Format(“{0}1{1}3{2}5{3}7{4}9”),
(i&0x100)!=0?”-“:”,
运算符[(i>>0)和3],
运算符[(i>>2)和3],
运算符[(i>>4)和3],
运算符[(i>>6)和3]),String.Empty);
...
}
否则,如果更深奥一些,这肯定会更快:

var opstrings = "+-*/" ;
var operators = new Func<int, int, int>[] {
  (a, b) => a + b,
  (a, b) => a - b,
  (a, b) => a * b,
  (a, b) => a / b, } ;
for (int i = 0 ; i < 0x200 ; ++i)
{
  var stack = 0 ; // seed value
  var last  = 0 ; // imitate + for lowest precedence
  var value =(i & 0x100) != 0 ? -1 : 1 ;

  for (int j = 0 ; j < 5 ; ++j)    // extra item to force last reduction
  {
    var oper  = (i >> j * 2) & 3 ; // "input" operator
    var input =  3  + j * 2 ;      // "input" number
    if (oper / 2 <= last / 2)      // reduce below top?
    {
      stack = operators[last] (stack, value) ;
      last  = oper  ;              // shift operator
      value = input ;              // shift number
    }
    else                           // reduce top
      value = operators[oper] (value, input) ;
  }

  var result  = stack ;
  if (result == 3 || result == 47 || result == 18)
    Debug.WriteLine ("{0}1{1}3{2}5{3}7{4}9 = {5}",
      (i & 0x100) != 0 ? "-" : "",
      opstrings[(i >> 0) & 3],
      opstrings[(i >> 2) & 3],
      opstrings[(i >> 4) & 3],
      opstrings[(i >> 6) & 3],
      result) ;
}
var opstrings=“+-*/”;
变量运算符=新函数[]{
(a,b)=>a+b,
(a,b)=>a-b,
(a,b)=>a*b,
(a,b)=>a/b,};
对于(int i=0;i<0x200;++i)
{
var stack=0;//种子值
var last=0;//模仿+表示最低优先级
var值=(i&0x100)!=0?-1:1;
对于(int j=0;j<5;++j)//强制最后一次缩减的额外项
{
var oper=(i>>j*2)&3;/“输入”运算符
var输入=3+j*2;/“输入”编号
如果(操作/2>0)&3],
opstrings[(i>>2)和3],
opstrings[(i>>4)和3],
opstrings[(i>>6)和3],
结果);
}

WWWWTTTTFFFF???谁会写这样的代码?wwwttttffff???谁会写这样的代码?感谢Jon-从未想过使用多个from…就像在sql中从客户、订单中选择*一样。我写了这篇博客,并将代码放在测试中,以确保它适用于这里的所有示例。感谢Jon-从未想过使用多个from。。。就像在sql中,从客户、订单中选择*一样。我在博客上写了这篇文章,并在测试中添加代码,以确保它适用于这里的所有示例。Cheers Cine。我在给你分数或Jon之间左右为难。我喜欢你答案的简单性。Cheers Cine。我在给你分数或Jon之间左右为难。我喜欢你的answ的简单性呃。Anton我无法理解让你的第二个Func示例在我的测试工具中运行的代码看起来像是一些虽然很刺激的代码!它实际上是不正确的!但是我修复了它。只有当计算器中只有两个操作符优先级且所有操作符都是二进制的时候,这种优化才有效。Anton我无法理解要获得的代码在我的测试工具中使用的第二个Func示例看起来像是一些发人深省的代码!它实际上是不正确的!但我已经修复了它。只有在计算器中只有两个运算符优先级且所有运算符都是二进制的情况下,此优化才有效。