• 表达式:使用API创建表达式树(1)


    表达式树可使用Expressions类的静态工厂方法来创建。这种用API的方式创建给予我们在编程极大的灵活性,MSDN上关于表达式的例子也不少,但在使用过程中还是会遇到许多麻烦,对有的表达式类,介绍得不是太清楚。这里把一些常见的表达示类的使用整理了下。
     
    BinaryExpression类: 是表示包含二元运算符的表达式。

      比如构建形如 (100+88)是个典型的 a+b 式的二元计算,表达式代码如下

    BinaryExpression binaryexp = Expression.MakeBinary
                     (ExpressionType.Add, Expression.Constant(100), Expression.Constant(88));
    Console.WriteLine(Expression.Lambda(binaryexp).Compile().DynamicInvoke());

    输出: 188


    MakeBinary是在Expressions中定义的一个静态工厂方法(根据ExpressionType来选择调用),最终调用的是Expression.Add 静态方法
    所以是与下面操作等效的

    BinaryExpression binaryexp = Expression.Add(Expression.Constant(100), Expression.Constant(88));


    a+b的值类型的操作比较简单,但如果是 "100"+"88" 呢,改下上面的操作

    BinaryExpression binaryexp = Expression.Add(Expression.Constant("100"), Expression.Constant("88"));
    Console.WriteLine(Expression.Lambda(binaryexp).Compile().DynamicInvoke());


    但这时会报错 “没有为类型“System.String”和“System.String”定义二进制运算符 Add”,这是怎么回事,在我们代码时如果写 string s= "100"+"88";是没错的啊。实际上字串的 +  在生成IL代码时,会转换成 string 的 Concat 扩展方法来操作。因此要实现如  "100"+"88" 还是稍显麻烦

    第一步:获取Concat方法的MethodInfo

        MethodInfo mif = typeof(string).GetMethods().First(m => m.Name == "Concat" && m.GetParameters().Length ==2);
        因为Concat的参数是可变的方法参数,获取MethodInfo,一定要加上m.GetParameters().Length=实际调用时的参数个数据,不然会出现参数不匹配错误。

    第二步:使用MakeBinary的另一个重载方法
        

        BinaryExpression binaryexp = Expression.Add(Expression.Constant("100"), Expression.Constant("88"), mif);
        Console.WriteLine(Expression.Lambda(binaryexp).Compile().DynamicInvoke());


      输出: 10088


    回头再看 Expression.Add 的实现

     if (!(method == (MethodInfo) null))
            return Expression.GetMethodBasedBinaryOperator(ExpressionType.Add, left, right, method, true);
          if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type))
            return (BinaryExpression) new SimpleBinaryExpression(ExpressionType.Add, left, right, left.Type);
          else
            return Expression.GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Add, "op_Addition", left, right, true);


    从中看出,当参数年method为null 时,实际上要检查 TypeUtils.IsArithmetic(left.Type),而IsArithmetic的定义为

      internal static bool IsArithmetic(Type type)
        {
          type = TypeUtils.GetNonNullableType(type);
          if (!type.IsEnum)
          {
            switch (Type.GetTypeCode(type))
            {
              case TypeCode.Int16:
              case TypeCode.UInt16:
              case TypeCode.Int32:
              case TypeCode.UInt32:
              case TypeCode.Int64:
              case TypeCode.UInt64:
              case TypeCode.Single:
              case TypeCode.Double:
                return true;
            }
          }
          return false;
        }



    所以Expression.Add(Expression.Constant("100"), Expression.Constant("88"))在不给定操作方法时,会报错。当指定操作方法时,表达式虽然用tostring 是  "100"+"88" ,但调用的操作方法是 string.Concat。就象用方法表达式一样

     MethodCallExpression methExp = Expression.Call(mif, Expression.Constant("100"), Expression.Constant("88"));

     因此在调用  Expression.Lambda(binaryexp).Compile().DynamicInvoke();和 Expression.Lambda(methExp).Compile().DynamicInvoke();的结果是一样的

     另外从 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) 前部分看,Add方法是要求类型完全相同,在看上去可行的表达式 Expression.Add(Expression.Constant(100), Expression.Constant(88.0)) (后面是Double类型 ),也会报错。而就当改为
     Expression.Add(Expression.Constant((Double)100), Expression.Constant(88.0)) 或 Expression.Add(Expression.Constant(100.0), Expression.Constant(88.0)) 。

  • 相关阅读:
    python_摘要_加密
    python_计算器
    python_选课系统
    飞行员配对方案问题 【网络流24题】
    方格取数 【网络流24题】【最小割】
    P2402 奶牛隐藏【二分】【最大流】
    P2172 [国家集训队]部落战争【最小路径覆盖】
    最小路径覆盖问题【网络流24题】
    P2057 [SHOI2007]善意的投票 / [JLOI2010]冠军调查 [最小割] [二分图]
    P2053 [SCOI2007]修车【zkw费用流】
  • 原文地址:https://www.cnblogs.com/athinker/p/3591954.html
Copyright © 2020-2023  润新知