學習筆記: Expression表達式目錄樹詳解和擴展封裝


1. 表達式目錄樹:語法樹,或者說是一種數據結構;可以被我們解析

Func<int, int, int> func = (m, n) => m * n + 2;// new Func<int, int, int>((m, n) => m * n + 2);
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;//lambda表達式聲明表達式目錄樹
                                                           //Expression<Func<int, int, int>> exp1 = (m, n) =>//只能一行 不能有大括號
                                                           //    {
                                                           //        return m * n + 2;
                                                           //    };
                                                           //Queryable    //a=>a.Id>3

//表達式目錄樹:語法樹,或者說是一種數據結構;可以被我們解析
int iResult1 = func.Invoke(12, 23);
int iResult2 = exp.Compile().Invoke(12, 23);//可以轉換過去

編譯后生成代碼

image

即下面這段

ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "m");    //聲明參數表達式
ParameterExpression parameterExpression2 = Expression.Parameter(typeof(int), "n");
var mutiply = Expression.Multiply(parameterExpression, parameterExpression2);  //乘法表達式 m*n
var constant = Expression.Constant(2, typeof(int));             //常量表達式
var add = Expression.Add(mutiply, constant);                  //加法表達式

Expression<Func<int, int, int>> expression =   //組合
     Expression.Lambda<Func<int, int, int>>(add, new ParameterExpression[] {
     parameterExpression,
     parameterExpression2
});

給出一個表達式 Expression<Func<People, bool>> lambda = x => x.Id.ToString().Equals("5");

自己拼裝表達式目錄樹

{

                ParameterExpression parameterExpression = Expression.Parameter(typeof(People), "x");
                 var field = Expression.Field(parameterExpression, typeof(People).GetField("Id"));
                 var toString = typeof(People).GetMethod("ToString");
                 var toStringCall = Expression.Call(field, toString, new Expression[0]);
                 var equals = typeof(People).GetMethod("Equals");
                 var constant = Expression.Constant("5", typeof(string));
                 var equalsCall = Expression.Call(toStringCall, equals, new Expression[] { constant });
                 Expression<Func<People, bool>> expression =
                     Expression.Lambda<Func<People, bool>>(equalsCall, new ParameterExpression[]
                         {
                         parameterExpression
                         });

                expression.Compile().Invoke(new People()
                 {
                     Id = 11,
                     Name = "Eleven",
                     Age = 31
                 });
             }

表達式目錄樹作用是什么呢

可以用來代替 反射 下面是 類型轉換 測試反射與表達式樹性能

image

static void Main(string[] args)
{
     try
     {

        {
             Console.WriteLine("********************MapperTest********************");
             ExpressionTest.MapperTest();
         }
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.Message);
     }
     Console.Read();
}

/// <summary>
/// 認識/拼裝 表達式目錄樹
/// 拼裝表達式
/// 應用
/// </summary>
public class ExpressionTest
{
     public static void MapperTest()
     {
         People people = new People()
         {
             Id = 11,
             Name = "Eleven",
             Age = 31
         };

        long common = 0;
         long generic = 0;
         long cache = 0;
         long reflection = 0;
         long serialize = 0;
         {
             Stopwatch watch = new Stopwatch();
             watch.Start();
             for (int i = 0; i < 1000000; i++)
             {
                 PeopleCopy peopleCopy = new PeopleCopy()
                 {
                     Id = people.Id,
                     Name = people.Name,
                     Age = people.Age
                 };
             }
             watch.Stop();
             common = watch.ElapsedMilliseconds;
         }
         {
             Stopwatch watch = new Stopwatch();
             watch.Start();
             for (int i = 0; i < 1000000; i++)
             {
                 PeopleCopy peopleCopy = ReflectionMapper.Trans<People, PeopleCopy>(people);
             }
             watch.Stop();
             reflection = watch.ElapsedMilliseconds;
         }
         {
             Stopwatch watch = new Stopwatch();
             watch.Start();
             for (int i = 0; i < 1000000; i++)
             {
                 PeopleCopy peopleCopy = SerializeMapper.Trans<People, PeopleCopy>(people);
             }
             watch.Stop();
             serialize = watch.ElapsedMilliseconds;
         }
         {
             Stopwatch watch = new Stopwatch();
             watch.Start();
             for (int i = 0; i < 1000000; i++)
             {
                 PeopleCopy peopleCopy = ExpressionMapper.Trans<People, PeopleCopy>(people);
             }
             watch.Stop();
             cache = watch.ElapsedMilliseconds;
         }
         {
             Stopwatch watch = new Stopwatch();
             watch.Start();
             for (int i = 0; i < 1000000; i++)
             {
                 PeopleCopy peopleCopy = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);
             }
             watch.Stop();
             generic = watch.ElapsedMilliseconds;
         }

        Console.WriteLine($"common = { common} ms");
         Console.WriteLine($"reflection = { reflection} ms");
         Console.WriteLine($"serialize = { serialize} ms");
         Console.WriteLine($"cache = { cache} ms");
         Console.WriteLine($"generic = { generic} ms");

    }


}

public class ReflectionMapper
{
     /// <summary>
     /// 反射
     /// </summary>
     /// <typeparam name="TIn"></typeparam>
     /// <typeparam name="TOut"></typeparam>
     /// <param name="tIn"></param>
     /// <returns></returns>
     public static TOut Trans<TIn, TOut>(TIn tIn)
     {
         TOut tOut = Activator.CreateInstance<TOut>();
         foreach (var itemOut in tOut.GetType().GetProperties())
         {
             var propIn = tIn.GetType().GetProperty(itemOut.Name);
             itemOut.SetValue(tOut, propIn.GetValue(tIn));
         }
         foreach (var itemOut in tOut.GetType().GetFields())
         {
             var fieldIn = tIn.GetType().GetField(itemOut.Name);
             itemOut.SetValue(tOut, fieldIn.GetValue(tIn));
         }
         return tOut;
     }

    public static TOut Trans1<TIn, TOut>(TIn tIn)
     {
         TOut tOut = Activator.CreateInstance<TOut>();
         foreach (var prop in typeof(TOut).GetProperties())
         {
             var val = tIn.GetType().GetProperty(prop.Name).GetValue(tIn);
             prop.SetValue(tOut, val);
         }
         foreach (var field in typeof(TOut).GetFields())
         {
             var val = tIn.GetType().GetField(field.Name).GetValue(tIn);
             field.SetValue(tOut, val);
         }
         return tOut;
     }

}

/// <summary>
/// 使用第三方序列化反序列化工具
///
/// 還有automapper
/// </summary>
public class SerializeMapper
{
     /// <summary>
     /// 序列化反序列化方式
     /// </summary>
     /// <typeparam name="TIn"></typeparam>
     /// <typeparam name="TOut"></typeparam>
     public static TOut Trans<TIn, TOut>(TIn tIn)
     {
         return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(tIn));
     }
}

/// <summary>
/// 生成表達式目錄樹 緩存
/// </summary>
public class ExpressionMapper
{
     private static Dictionary<string, object> _Dic = new Dictionary<string, object>();

    /// <summary>
     /// 字典緩存表達式樹
     /// </summary>
     /// <typeparam name="TIn"></typeparam>
     /// <typeparam name="TOut"></typeparam>
     /// <param name="tIn"></param>
     /// <returns></returns>
     public static TOut Trans<TIn, TOut>(TIn tIn)
     {
         string key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
         if (!_Dic.ContainsKey(key))
         {
             ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
             List<MemberBinding> memberBindingList = new List<MemberBinding>();
             foreach (var item in typeof(TOut).GetProperties())
             {
                 MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                 MemberBinding memberBinding = Expression.Bind(item, property);
                 memberBindingList.Add(memberBinding);
             }
             foreach (var item in typeof(TOut).GetFields())
             {
                 MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                 MemberBinding memberBinding = Expression.Bind(item, property);
                 memberBindingList.Add(memberBinding);
             }
             MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
             Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
             {
                 parameterExpression
             });
             Func<TIn, TOut> func = lambda.Compile();//拼裝是一次性的
             _Dic[key] = func;
         }
         return ((Func<TIn, TOut>)_Dic[key]).Invoke(tIn);
     }
}

     /// <summary>
     /// 生成表達式目錄樹  泛型緩存
     /// </summary>
     /// <typeparam name="TIn"></typeparam>
     /// <typeparam name="TOut"></typeparam>
     public class ExpressionGenericMapper<TIn, TOut>//Mapper`2
     {
         private static Func<TIn, TOut> _FUNC = null;
         static ExpressionGenericMapper()
         {
             ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
             List<MemberBinding> memberBindingList = new List<MemberBinding>();
             foreach (var item in typeof(TOut).GetProperties())
             {
                 MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                 MemberBinding memberBinding = Expression.Bind(item, property);
                 memberBindingList.Add(memberBinding);
             }
             foreach (var item in typeof(TOut).GetFields())
             {
                 MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                 MemberBinding memberBinding = Expression.Bind(item, property);
                 memberBindingList.Add(memberBinding);
             }
             MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
             Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
             {
                     parameterExpression
             });
             _FUNC = lambda.Compile();//拼裝是一次性的
         }
         public static TOut Trans(TIn t)
         {
             return _FUNC(t);
         }
     }


/// <summary>
/// 實體類
/// </summary>
public class People
{
     public int Age { get; set; }
     public string Name { get; set; }

    public int Id;
}

/// <summary>
/// 實體類Target
/// </summary>
public class PeopleCopy
{
     public int Age { get; set; }
     public string Name { get; set; }//ShortName

    public int Id;
}

疑問點: 這個委托放在 靜態字典 與  靜態泛型緩存 為什么差了1個數量級

Dictionary<TKey, TValue>維護一個哈希表。

它的枚舉器將遍歷散列表中的存儲桶,直到找到一個非空的存儲桶,然后返回該存儲桶中的值。
一旦字典變大,這個操作變得昂貴。


而 泛型緩存    private static Func<TIn, TOut> _FUNC = null;

如果 TIn, TOut 類型有變動, 會導產生不同的副本.

簡單描述下: TIn, TOut 類型有變動, 因為是泛型類  ExpressionGenericMapper<TIn, TOut>,會重新生成一個類, 並調用靜態構造 給泛型緩存賦值, 變動前的泛型類,靜態泛型緩存仍存在


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM