<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【C#語法糖 Lambda】2 - 表達式樹與LINQ

      一、聲明

        曾經遇到一個這樣的場景:

      GetEntities(a => a.OrderKindCodeId == 16 && a.IsDeleted, this.DefaultContext)
      protected IEnumerable<TEntity> GetEntities(Expression<Func<TDto, bool>> expression, IRepositoryContext context)

        我就很奇怪,明明a => a.OrderKindCodeId == 16 && a.IsDeleted是Lambda表達式,為什么入參是表示式樹呢?一次偶然調試中發現,原來C#支持表達式樹的聲明像Lambda一樣寫(當然有一定局限)。

        上述報錯,是編譯器無法推斷弱類型是表達式樹類型還是Lambda類型,需要指定類型:

      Func<string, string, bool> lambda = (a,b) => a.StartsWith(b);
      Expression<Func<string, string, bool>> e = (a, b) => a.StartsWith(b);
      
      var expressionToLambda = e.Compile(); // 將表達式樹轉化成lambda表達式,故類型與e相同,但內容與e有區別
      var typeIsEqual = expressionToLambda.GetType() == lambda.GetType(); // true
      bool isEqual = lambda.Equals(expressionToLambda); // false

        不同的原因應該是.Compile()的鍋,此處不研究。

        換一種方法聲明表達式樹:

      static Func<string, bool> buildlambda(Expression<Func<string, bool>> exp1, Expression<Func<string, bool>> exp2)
      {
          ParameterExpression parameter = Expression.Parameter(typeof(string));
          Expression left = exp1.Body;
          Expression right = exp2.Body;
          BinaryExpression AndAlso = Expression.AndAlso(left, right);
          return Expression.Lambda<Func<string, bool>>(AndAlso, parameter).Compile();
      }

        看起來很正常,但運行時compile會報錯:

      System.InvalidOperationException:“從作用域“”引用了“System.String”類型的變量“a”,但該變量未定義”

        運算過程出錯,因為找不到參數——啥意思?上例的錯誤其實相當于這樣:

      Expression<Func<string, string, bool>> e = (a, b) => a.StartsWith(b);
      var e1 = Expression.Lambda(e.Body);
      bool c1 = e == e1; // false

      e1 = Expression.Lambda(e.Body, e.Parameters); // e1是Expression<T>類型,指定了參數,讓運算有個目標
      var e2 = e1 as Expression; // e2是LambdaExpression類型
      c1 = e == e1; // false,類型不同

       

      二、存儲結構

        表達式樹是有穩定性的,它由一個一個節點掛成一棵樹,那怎么修改它?動一棵樹,那必然是要遍歷的,要遞歸。

        問題又來了,構建一個表達式樹如此費勁(不使用lambda表達式下)干嘛要用它——表達式樹存在的意義?

       

      三、意義與應用

        3 - 1 為什么需要表達式樹

        表達式樹的應用,最后還是要.Compile()成lambda表達式,那為什么不直接用lambda?

        ⑴ 調試可見方法如何實現

        ⑵ Lambda表達式能轉換成表達式樹,然后由其他代碼處理,從而達到在不同執行環境中執行等價的行為。

        Linq To SQL :將源語言(比如C#)生成一個表達式樹,其結果作為一個中間格式,再將其轉換成目標平臺上的本地語言(比如SQL)。

        那么這個中間格式直接傳lambda表達式行不行?

        測試了一下,數據庫響應速度特別慢,可能還會發生超時。僅就這個原因,也必須用表達式樹了:

        看用時:

       

        3 - 2 ExpressionVisitor

        上述提及與數據庫交互,那就涉及節點值問題(例如節點是一個函數的值,我們希望直接傳函數結果而不是傳函數),盡量處理得干凈一些,這就需要修改(/重構)樹,可以使用ExpressionVisitor類。

        ExpressionVisitor應該是一個抽象類,程序員按需求繼承重寫。

        這個類主要處理好Parameter和各個節點類型,入口函數應該是Visit(Expression exp),此處僅列出一部分:

              public virtual Expression Visit(Expression exp)
              {
                  if (exp == null)
                      return exp;
                  switch (exp.NodeType)
                  {
                      case ExpressionType.And: // +
                      case ExpressionType.AndAlso: // 并且
                      case ExpressionType.LessThan: // 小于
                      case ExpressionType.GreaterThan: // 大于
                      case ExpressionType.Equal: // 等于
                      case ExpressionType.NotEqual: // 不等于
                          return this.VisitBinary((BinaryExpression)exp);
                      case ExpressionType.Constant: // 常數
                          return this.VisitConstant((ConstantExpression)exp);
                      case ExpressionType.Parameter: // 參數
                          return this.VisitParameter((ParameterExpression)exp);
                      case ExpressionType.MemberAccess: //從字段或屬性進行讀取的運算,如 obj.SampleProperty
                          return this.VisitMemberAccess((MemberExpression)exp);
                      case ExpressionType.Call: // 方法調用
                          return this.VisitMethodCall((MethodCallExpression)exp);
                      case ExpressionType.Lambda: // Lambda表達式
                          return this.VisitLambda((LambdaExpression)exp);
                      default:
                          throw new Exception(string.Format("Unhandled expression type: '{0}'", exp.NodeType));
                  }
              }
      View Code

        應用上例,改動一下:

         ExpressionVisitorTest:

          public class ExpressionVisitorTest
          {
              public ExpressionVisitorTest() { }
      
              public Expression Visit(Expression exp)
              {
                  if (exp == null)
                      return exp;
                  switch (exp.NodeType)
                  {
                      case ExpressionType.Parameter:
                          return VisitParameter((ParameterExpression)exp);
                      case ExpressionType.NotEqual:
                          return this.VisitBinary((BinaryExpression)exp);
                      case ExpressionType.MemberAccess:
                          return this.VisitMemberAccess((MemberExpression)exp);
                      case ExpressionType.Constant:
                          return this.VisitConstant((ConstantExpression)exp);
                      default: return exp;
                  }
              }
      
              protected virtual Expression VisitBinary(BinaryExpression b)
              {
                  Expression left = this.Visit(b.Left);
                  Expression right = this.Visit(b.Right);
                  Expression conversion = this.Visit(b.Conversion);
                  if (left != b.Left || right != b.Right || conversion != b.Conversion)
                  {
                      if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null)
                          return Expression.Coalesce(left, right, conversion as LambdaExpression);
                      else
                          return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method);
                  }
                  return b;
              }
      
              public Expression VisitMemberAccess(MemberExpression exp)
              {
                  Expression body = Visit(exp.Expression);
                  if (body != exp.Expression)
                      return Expression.MakeMemberAccess(exp, exp.Member);
                  return exp;
              }
      
              public Expression VisitParameter(ParameterExpression exp)
              {
                  return Parameter;
              }
      
              protected virtual Expression VisitConstant(ConstantExpression c)
              {
                  return c;
              }
      
              public ParameterExpression Parameter
              {
                  get;
                  set;
              }
      }
      View Code

       

        先看看要啥效果:

         ExpressionVisitor visitor = new ExpressionVisitorInstance();
      string testStr = true ? "0" : "123"; Expression<Func<string, bool>> aa = a => a != testStr; var bb = visitor.Visit(aa); isequal = bb.Equals(aa); // false

         (下載ExpressionVisitor.cs

        例如重寫VisitMemberAccess方法:

          public class ExpressionVisitorInstance : ExpressionVisitor
          {
              protected override Expression VisitMemberAccess(MemberExpression m)
              {
                  Expression expr = base.VisitMemberAccess(m);
                  return SimplyMemberAccess(expr);
              }
      
              private static Expression SimplyMemberAccess(Expression expr)
              {
                  MemberExpression me = expr as MemberExpression;
                  if (me == null) return expr;
      
                  object target;
                  if (me.Expression == null)
                      target = null;
                  else if (me.Expression is ConstantExpression)
                      target = (me.Expression as ConstantExpression).Value;
                  else
                      return expr;
      
                  return Expression.Constant(me.Member.GetValue(target));
              }
          }
      View Code

        MemberExpression的屬性:

      MemberExpression

      CanReduce

      能否化簡

      Expression

      值表達式

      Member

      Reflection.RtFieldInfo類型,可處理此處獲得真實值

      NodeType

      節點類型

      Type

      值類型

        處理反射的幫助類:

          public static class ReflectionHelper
          {
              public static object GetValue(this MemberInfo member, object component)
              {
                  if (component == null && !member.CanGetFromNull()) return null;
      
                  if (member is PropertyInfo)
                      return ((PropertyInfo)member).GetValue(component, null);
                  if (member is FieldInfo)
                      return ((FieldInfo)member).GetValue(component);
      
                  MethodInfo method = member as MethodInfo;
                  if (method != null && typeof(void) != method.ReturnType && method.GetParameters().Length == 0)
                  {
                      return method.Invoke(component, null);
                  }
      
                  return null;
              }
      
              private static bool CanGetFromNull(this MemberInfo member)
              {
                  if (member is PropertyInfo)
                      return ((PropertyInfo)member).GetGetMethod().IsStatic;
                  else if (member is FieldInfo)
                      return ((FieldInfo)member).IsStatic;
                  else if (member is MethodBase)
                      return ((MethodBase)member).IsStatic;
                  else
                      return false;
              }
          }
      View Code

       

        3 - 3 表達式樹的其他作用:

        不同類型數字相加,詳見 http://mng.bz/9m8i

              public static T Add<T>(T a, T b)
              {
                  ParameterExpression left = Expression.Parameter(typeof(T), "a"),
                   right = Expression.Parameter(typeof(T), "b");
                  Expression Add = Expression.Add(left, right);
      
                  Func<T, T, T> add = Expression.Lambda<Func<T, T, T>>(Add, left, right).Compile();
                  return add(a, b);
              }

        但略感到尷尬的是,現在使用的.net 4.6.1已經能支持類型推斷了,會推斷一個“合適的類型”,也即意味著不用人工去強轉類型了:

          int d1 = 1;
          double d2 = 2.1;
          float d4 = 5.5f;
          long d5 = (long)10;
          var d3 = d1+ d2 + d5 + d4; // 存在從int到double的隱式轉換

       

      參考:

      [0] 深入C# 第三版

      [1] http://www.rzrgm.cn/FlyEdward/archive/2010/12/06/Linq_ExpressionTree7.html

      [2] https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/how-to-modify-expression-trees

       

      posted @ 2020-01-15 22:08  Carcar019  閱讀(426)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 成年女人免费v片| 天天躁夜夜躁狠狠喷水| 国产精品一亚洲av日韩| 亚洲精品综合久中文字幕| 最新亚洲av日韩av二区| 人妻出轨av中文字幕| 人妻少妇精品视频专区| 热久久美女精品天天吊色| 日本深夜福利在线观看| 国产黄色av一区二区三区| 久久综合亚洲色一区二区三区| 精品无码久久久久久久久久| 国产精品国产片在线观看| 亚洲人成网站在线播放2019| 亚洲一区二区约美女探花| 日韩高清免费一码二码三码| 久久av无码精品人妻出轨| 亚洲国产综合精品2020| 昆山市| 日韩精品亚洲专区在线播放| 四虎永久精品在线视频| 无码成人午夜在线观看| 国产精品普通话国语对白露脸| 亚洲VA中文字幕无码久久| 中文字幕人妻无码一夲道| 久久大香萑太香蕉av黄软件 | 国产精品免费看久久久| 久久97超碰色中文字幕蜜芽| 狂躁女人双腿流白色液体| 一区二区三区国产亚洲网站| 色吊丝免费av一区二区| 亚洲国产美女精品久久久| 18禁黄无遮挡网站免费| 四虎永久播放地址免费| 国精品91人妻无码一区二区三区| 国产精品第一区亚洲精品| 久久亚洲中文无码咪咪爱| 日本无遮挡吸乳视频| 精品亚洲国产成人av在线| 亚洲国模精品一区二区| 亚洲的天堂在线中文字幕|