參考文章html
演變過程node
using System; namespace lq1 { class Program { public delegate void Tesk(int x); public delegate int TeskPara(int x); static void Main(string[] args) { new Program().Run(); } public void Show(int x) { Console.WriteLine("Show"); } public void Run() { // Lambda演變歷史 { // .net framework 1.0/1.1 Tesk tesk = new Tesk(this.Show); tesk.Invoke(1); } int i = 0; { // .net framework 2.0,匿名方法,增長delegate關鍵字,能夠訪問局部變量 Tesk tesk = new Tesk(delegate (int x) { Console.WriteLine("Show" + i); }); tesk.Invoke(2); } { // .net framework 3.0 移除delegate關鍵字,增長 => 語法(goes to) Tesk tesk = new Tesk((int x) => { Console.WriteLine("Show" + i); }); tesk.Invoke(3); } { // 能夠省略參數類型,參數類型根據委託自動推斷 Tesk tesk = new Tesk((x) => { Console.WriteLine("Show" + i); }); tesk.Invoke(3); } { // 只有一個參數或一行代碼時省略括號 Tesk tesk = new Tesk(x => Console.WriteLine("Show" + i)); tesk.Invoke(3); } { // 省略實例委託代碼 Tesk tesk = x => Console.WriteLine("Show" + i); tesk.Invoke(3); } { // 有返回值且有一行代碼時,能夠直接寫返回值(省略 return) TeskPara tesk = x => x + 1; tesk.Invoke(5); Func<int, int> func = x => x + 2; func.Invoke(5); } } } }
概述說明sql
Lambda
表達式是一個特殊的匿名函數,是一種高效的相似於函數式編程的表達式,簡化開發中須要編寫的代碼量數據庫
能夠包含表達式和語句,而且可用於建立委託或表達式目錄樹類型,支持帶有可綁定到委託或表達式樹的輸入參數的內聯表達式express
全部Lambda
表達式都使用Lambda
運算符=>
,運算符的左邊是輸入參數(若是有),右邊是表達式或語句塊編程
Lambda
表達式不能在委託鏈中進行刪(-=
)操做,由於每一個表達式的名稱都不同c#
在C# 3.0中,引進了關鍵字叫作var
,var
容許聲明一個新變量,它的類型是從用來初始化器變量的表達式裏隱式的推斷出來的,即在聲明時,不須要給它定義類型,它會根據它的初始化器表達式來推斷出它的類型數組
var
自己不是類型,而是向編譯器發出一條用來推斷和分配類型的指令,所以,隱式類型也叫推斷類型,由編輯器自動根據表達式推斷出對象的最終類型緩存
隱式類型的本地變量是強類型變量(就好像您已經聲明該類型同樣),但由編譯器肯定類型數據結構
var Name = "李白"; var Age = 18; var Interest = new List<string>{"唱歌","閱讀"}
概述說明
字面意思:沒有名字的類型
演變歷史
public void Starting() { { // 使用 object 聲明 object model = new { id = 1, name = "libai" }; //Console.WriteLine(model.id); 強類型語言,編譯器檢測不到object類型中有id屬性 } { // 使用 dynamic 聲明,動態類型,避開編譯器檢查 dynamic model = new { id = 2, name = "libai" }; Console.WriteLine(model.id); Console.WriteLine(model.age); // 運行時出錯 } { // 使用 var 聲明,匿名類型,自動推斷,聲明後的屬性是隻讀的 var model = new { id = 3, name = "libai" }; Console.WriteLine(model.id); //Console.WriteLine(model.age); 編譯器檢測(自動推斷)無age字段 } }
概述說明
擴展方法:容許在不修改類型的內部代碼的狀況下爲類型添加獨立的行爲
擴展方法只能定義在 非泛型的靜態類中,使用 static
修飾,參數使用this
關鍵字 修飾要擴展的類。就是說擴展方法的第一個參數必須是this
關鍵開頭而後經跟要擴展的對象類型,而後是擴展對象在運行時的實例對象引用
擴展方法是一種特殊的靜態方法,能夠像擴展類型上的實例方法同樣進行調用,能向現有類型「添加」方法,而無須建立新的派生類型、從新編譯或以其餘方式修改原始類型
在使用時編譯器認爲一個表達式要使用一個實例方法,可是沒有找到,須要檢查導入的命名空間和當前命名空間裏全部的擴展方法,並匹配到適合的方法
示例一:簡單定義
public static class Extend { public static int ToInt(this int? k) { return k ?? 0; } }
示例二:簡單定義
public interface ILog { void log(string message,LogLevel logLevel); } public static class ILogExtensions { //記錄調試信息 public static void LogDebug(this ILog logger,string message) { if(true) //判斷日誌配置中是否容許輸入Debug類型的日誌 { logger?.Log($"{message}",LogLevel.Debug); } } }
示例三:模擬
where
方法
using System; using System.Collections.Generic; namespace lq2 { class Program { static void Main(string[] args) { List<User> list = new List<User> { new User(){uid=1,uname="a1",age=18,gender=0 }, new User(){uid=2,uname="a2",age=28,gender=1 }, new User(){uid=3,uname="a3",age=23,gender=1 }, new User(){uid=4,uname="a4",age=18,gender=0 }, new User(){uid=5,uname="a5",age=33,gender=1 } }; var d1 = list.MyWhere(x => x.uid > 3); Console.WriteLine(d1.Count); var d2 = list.MyWhere(x => x.age >= 18 && x.gender == 0); Console.WriteLine(d2.Count); } } public class User { public int uid { get; set; } public int age { get; set; } public string uname { get; set; } public int gender { get; set; } } public static class Extend { public static List<T> MyWhere<T>(this List<T> rouse, Func<T, bool> func) { List<T> list = new List<T>(); foreach (var item in rouse) { if (func(item)) { list.Add(item); } } return list; } } }
表達式樹,Expression
(System.Linq.Expressions
),是一種數據結構體,用於存儲須要計算,運算的一種結構,這種結構能夠只是存儲,而不進行運算,或者說是描述不一樣變量和經常使用之間關係的一種數據結構
表達式目錄樹以數據形式表示語言級別代碼,數據存儲在樹形結構中,目錄樹中的每一個節點都表示一個表達式,簡單的說是一種語法樹,或者說是一種數據結構
表達式目錄樹不能有語句體,不能看成方法,不能有大括號,只能有一行代碼
第一種方式,快捷聲明,用
Lambda
聲明表達式目錄樹
示例一:普通類型
Expression<Func<int, int, int>> exp = (n, m) => n * m + 2;
示例二:實體類聲明
Expression<Func<User, bool>> lambda = x => x.age > 18;
第二種方式,手動拼裝目錄樹(原始方式),簡單示例
namespace e1 { using System; using System.Linq.Expressions; class Program { static void Main(string[] args) { // 以此表達式爲例,手動拼接,實現相同做用 Expression<Func<int, int, int>> func = (x, y) => x * y + 2; // 聲明變量表達式 ParameterExpression px = Expression.Parameter(typeof(int), "x"); ParameterExpression py = Expression.Parameter(typeof(int), "y"); // 聲明常量表達式 ConstantExpression constant = Expression.Constant(2, typeof(int)); // 聲明乘積表達式 BinaryExpression multiply = Expression.Multiply(px, py); // 聲明相加表達式 BinaryExpression add = Expression.Add(multiply, constant); // 聲明參數表達式 ParameterExpression[] parameters = new ParameterExpression[] { px, py }; // 生成表達式目錄樹 Expression<Func<int, int, int>> exp = Expression.Lambda<Func<int, int, int>>(add, parameters); // 表達式目錄樹生成委託 var ifunc = exp.Compile(); Console.WriteLine("委託結果:" + func.Compile().Invoke(1, 2)); Console.WriteLine("表達式樹:" + ifunc.Invoke(1, 2)); } } }
方法 | 類型 | 描述 |
---|---|---|
Expression.Parameter(...) | ParameterExpression | 表示一個命名參數(變量)表達式 |
Expression.Constant(...) | ConstantExpression | 表示具備常量值的表達式 |
Expression.Add(...) | BinaryExpression | 表示具備(+,-,*,/ )運算的表達式 |
Expression.Property/Field(...) | MemberExpression | 表示訪問屬性或字段 |
Expression.Call(...) | MethodCallExpression | 表示對靜態方法或實例方法的調用 |
Expression.Condition(...) | ConditionalExpression | 表示包含條件運算符的表達式 |
LambdaExpression | 描述一個Lambda表達式 | |
ListInitExpression | 表示包含集合初始值設定項的構造函數調用 | |
NewExpression | 表示構造函數調用 | |
NewArrayExpression | 表示建立新數組並可能初始化改數組的元素 | |
MemberMemberBinding | 表示初始化新建立對象的成員的成員 | |
MemberInitExpression | 表示調用構造函數並初始化新對象的一個或多個成員 | |
MemberAssignment | 表示初始化新建立對象的字段或屬性 | |
InvocationExpression | 表示將委託或Lambda表達式應用於參數表達式列表的表達式 | |
TypeBinaryExpression | 表示表達式和類型之間的操做 | |
UnaryExpression | 表示包含一元運算符的表達式 |
示例一:常量
static void Test1() { // lambda方式 Expression<Func<int>> func = () => 1 + 2; // 聲明常量表達式 ConstantExpression constant1 = Expression.Constant(1, typeof(int)); ConstantExpression constant2 = Expression.Constant(2, typeof(int)); // 聲明相加表達式 BinaryExpression add = Expression.Add(constant1, constant2); // 生成表達式目錄樹 Expression<Func<int>> exp = Expression.Lambda<Func<int>>(add); // 表達式目錄樹生成委託 var ifunc = exp.Compile(); Console.WriteLine(func.Compile().Invoke()); Console.WriteLine(ifunc.Invoke()); }
示例二:常量+變量(2.2示例)
namespace e1 { using System; using System.Linq.Expressions; class Program { static void Main(string[] args) { // 以此表達式爲例,手動拼接,實現相同做用 Expression<Func<int, int, int>> func = (x, y) => x * y + 2; // 聲明變量表達式 ParameterExpression px = Expression.Parameter(typeof(int), "x"); ParameterExpression py = Expression.Parameter(typeof(int), "y"); // 聲明常量表達式 ConstantExpression constant = Expression.Constant(2, typeof(int)); // 聲明乘積表達式 BinaryExpression multiply = Expression.Multiply(px, py); // 聲明相加表達式 BinaryExpression add = Expression.Add(multiply, constant); // 聲明參數表達式 ParameterExpression[] parameters = new ParameterExpression[] { px, py }; // 生成表達式目錄樹 Expression<Func<int, int, int>> exp = Expression.Lambda<Func<int, int, int>>(add, parameters); // 表達式目錄樹生成委託 var ifunc = exp.Compile(); Console.WriteLine("委託結果:" + func.Compile().Invoke(1, 2)); Console.WriteLine("表達式樹:" + ifunc.Invoke(1, 2)); } } }
示例一:特殊類型示例
namespace e1 { using System; using System.Linq.Expressions; using System.Reflection; class Program { static void Main(string[] args) { Test2(); } static void Test2() { // lambda方式 Expression<Func<User, bool>> func = (u) => u.uid.ToString().Equals("1"); // 聲明變量表達式 ParameterExpression x = Expression.Parameter(typeof(User), "x"); // 獲取字段 PropertyInfo property = typeof(User).GetProperty("uid"); // 獲取方法 MethodInfo toString = typeof(int).GetMethod("ToString", new Type[] { }); MethodInfo equals = typeof(string).GetMethod("Equals", new Type[] { typeof(string) }); // 設置常量表達式 ConstantExpression constant = Expression.Constant("1"); // 訪問字段表達式 MemberExpression propertyExp = Expression.Property(x, property); // 調用方法表達式 var tostringExp = Expression.Call(propertyExp, toString, new Expression[0]); var equalsExp = Expression.Call(tostringExp, equals, new Expression[] { constant }); // 生成表達式樹 Expression<Func<User, bool>> expression = Expression.Lambda<Func<User, bool>>(equalsExp, new ParameterExpression[] { x }); User user = new User { uid = 5 }; Console.WriteLine(func.Compile().Invoke(user)); Console.WriteLine(expression.Compile().Invoke(user)); } } public class User { public int uid { get; set; } } }
使用 ExpressionVisitor
解析表達式目錄樹,ExpressionVisitor
表示表達式樹的訪問者和重寫者
解析流程
ExpressionVisitor
這個訪問者類Visit
入口(開始)方法解析表達式(自動根據表達式類型執行相應類型的解析方法)Lambda
會區分參數和方法體,調度(自動)到更加專業的方法中解析(須要在次調用入口 Visit
方法)Visit
方法)示例一:常量
using System; using System.Linq.Expressions; namespace e2 { class Program { static void Main(string[] args) { Test1(); } static void Test1() { Expression<Func<int>> expression = () => 1; CustomVisitor visitor = new CustomVisitor(); var exp = visitor.Modify(expression); } } public class CustomVisitor : ExpressionVisitor { public Expression Modify(Expression expression) { return this.Visit(expression); } protected override Expression VisitConstant(ConstantExpression node) { Console.WriteLine("VisitConstant"); return base.VisitConstant(node); } } }
示例二:變量+常量,算術運算(二元運算類型【兩個數操做】)
using System; using System.Linq.Expressions; namespace e2 { class Program { static void Main(string[] args) { Test1(); } static void Test1() { // 1.建立表達式樹 Expression<Func<int, int>> expression = (y) => y + 2; // 2.建立訪問類實例(使用繼承是爲了演示過程) CustomVisitor visitor = new CustomVisitor(); // 3.調用入口方法,調用入口方法後就會自動進行默認解析(若是沒有定義解析過程的話) var exp = visitor.Modify(expression); } } // 繼承訪問類,演示過程 public class CustomVisitor : ExpressionVisitor { // 調用入口方法,開始解析,自動調用表達式類型對應的解析方法 public Expression Modify(Expression expression) { return this.Visit(expression); } // 4.調用二元表達式解析方法 protected override Expression VisitBinary(BinaryExpression node) { Console.WriteLine("VisitBinary"); // 4.1 判斷表達式操做類型 if (node.NodeType == ExpressionType.Add) { Expression left = this.Visit(node.Left); Expression right = this.Visit(node.Right); return Expression.Subtract(left, right); } return base.VisitBinary(node); } // 4.調用常量表達式解析方法 protected override Expression VisitConstant(ConstantExpression node) { Console.WriteLine("VisitConstant"); return base.VisitConstant(node); } } }
示例一:屬性+常量(二元運算)
using System; using System.Linq.Expressions; namespace e2 { class Program { static void Main(string[] args) { Test1(); } static void Test1() { Expression<Func<User, bool>> expression = (u) => u.age > 1; CustomVisitor visitor = new CustomVisitor(); var exp = visitor.Modify(expression); } } public class User { public int uid { get; set; } public int age { get; set; } } public class CustomVisitor : ExpressionVisitor { public Expression Modify(Expression expression) { return this.Visit(expression); } // 二元運算類型 protected override Expression VisitBinary(BinaryExpression node) { Console.WriteLine("VisitBinary"); if (node.NodeType == ExpressionType.Add) { Expression left = this.Visit(node.Left); Expression right = this.Visit(node.Right); return Expression.Subtract(left, right); } return base.VisitBinary(node); } // 屬性類型 protected override Expression VisitMember(MemberExpression node) { Console.WriteLine("VisitMember"); return base.VisitMember(node); } // 常量類型 protected override Expression VisitConstant(ConstantExpression node) { Console.WriteLine("VisitConstant"); return base.VisitConstant(node); } } }
示例二:方法(若是要自定義解析處理的話須要預先知道方法名纔可)
using System; using System.Linq.Expressions; namespace e2 { class Program { static void Main(string[] args) { Expression<Func<User, bool>> expression = (u) => u.name.Contains("1"); CustomVisitor visitor = new CustomVisitor(); visitor.Visit(expression); } } public class User { public int uid { get; set; } public int age { get; set; } public string name { get; set; } } public class CustomVisitor : ExpressionVisitor { public Expression Modify(Expression expression) { return this.Visit(expression); } // 方法表達式 protected override Expression VisitMethodCall(MethodCallExpression node) { Console.WriteLine("VisitMethodCall:"+ node.Method.Name); return node; } } }
運算符擴展方法
using System; using System.Linq.Expressions; namespace e2 { internal static class SqlOperator { internal static string ToSqlOperator(this ExpressionType type) { switch (type) { case (ExpressionType.AndAlso): case (ExpressionType.And): return "AND"; case (ExpressionType.OrElse): case (ExpressionType.Or): return "OR"; case (ExpressionType.Not): return "NOT"; case (ExpressionType.NotEqual): return "<>"; case ExpressionType.GreaterThan: return ">"; case ExpressionType.GreaterThanOrEqual: return ">="; case ExpressionType.LessThan: return "<"; case ExpressionType.LessThanOrEqual: return "<="; case (ExpressionType.Equal): return "="; default: throw new Exception("不支持該方法"); } } } }
表達式樹解析類
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace e2 { public class ConditionBuilderVisitor : ExpressionVisitor { private Stack<string> _StringStack = new Stack<string>(); public string Condition() { string condition = string.Concat(this._StringStack.ToArray()); this._StringStack.Clear(); return condition; } // 解析 二元表達式 類型 protected override Expression VisitBinary(BinaryExpression node) { if (node == null) throw new ArgumentNullException("BinaryExpression"); this._StringStack.Push(")"); base.Visit(node.Right);//解析右邊 this._StringStack.Push(" " + node.NodeType.ToSqlOperator() + " "); base.Visit(node.Left);//解析左邊 this._StringStack.Push("("); return node; } // 解析 屬性表達式 類型 protected override Expression VisitMember(MemberExpression node) { if (node == null) throw new ArgumentNullException("MemberExpression"); this._StringStack.Push(" [" + node.Member.Name + "] "); return node; } // 解析 常量表達式 類型 protected override Expression VisitConstant(ConstantExpression node) { if (node == null) throw new ArgumentNullException("ConstantExpression"); this._StringStack.Push(node.Value.ToString()); return node; } // 解析 方法表達式 類型 protected override Expression VisitMethodCall(MethodCallExpression m) { if (m == null) throw new ArgumentNullException("MethodCallExpression"); string format; switch (m.Method.Name) { case "StartsWith": format = "({0} LIKE '{1}%')"; break; case "Contains": format = "({0} LIKE '%{1}%')"; break; case "EndsWith": format = "({0} LIKE '%{1}')"; break; default: throw new NotSupportedException(m.NodeType + " is not supported!"); } this.Visit(m.Object); this.Visit(m.Arguments[0]); string right = this._StringStack.Pop(); string left = this._StringStack.Pop(); this._StringStack.Push(String.Format(format, left, right)); return m; } } }
調用執行
using System; using System.Linq.Expressions; namespace e2 { class Program { static void Main(string[] args) { Test1(); } static void Test1() { Expression<Func<User, bool>> expression = (u) => u.age > 1; expression = (u) => u.age > 1 && u.uid < 2; expression = (u) => u.age > 1 && (u.uid < 2 || u.age > 2); expression = (u) => u.age > 1 && u.name.Contains("李"); ConditionBuilderVisitor visitor = new ConditionBuilderVisitor(); var exp = visitor.Visit(expression); Console.WriteLine(visitor.Condition()); } } public class User { public int uid { get; set; } public int age { get; set; } } }
連接表達式擴展方法
using System; using System.Linq.Expressions; namespace e2 { // 創建新表達式 internal class NewExpressionVisitor : ExpressionVisitor { // 遍歷表達式類型,當遇到參數類型表達式時,替換爲咱們本身定義的參數 public ParameterExpression _NewParameter { get; private set; } public NewExpressionVisitor(ParameterExpression param) { this._NewParameter = param; } public Expression Replace(Expression exp) { return this.Visit(exp); } // 利用ExpressionVisitor統一參數 protected override Expression VisitParameter(ParameterExpression node) { return this._NewParameter; } } /// <summary> /// 合併表達式 And Or Not擴展 /// </summary> public static class ExpressionExtend { public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) { ParameterExpression newParameter = Expression.Parameter(typeof(T), "c"); NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter); var left = visitor.Replace(expr1.Body);// 從新生成了一個表達式目錄樹 var right = visitor.Replace(expr2.Body); var body = Expression.And(left, right); return Expression.Lambda<Func<T, bool>>(body, newParameter); } public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) { // 建立參數表達式 ParameterExpression newParameter = Expression.Parameter(typeof(T), "c"); // 生成一個新的表達式 NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter); var left = visitor.Replace(expr1.Body); var right = visitor.Replace(expr2.Body); var body = Expression.Or(left, right); return Expression.Lambda<Func<T, bool>>(body, newParameter); } public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expr) { var candidateExpr = expr.Parameters[0]; var body = Expression.Not(expr.Body); return Expression.Lambda<Func<T, bool>>(body, candidateExpr); } } }
解析表達式類
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace e2 { public class ConditionBuilderVisitor : ExpressionVisitor { private Stack<string> _StringStack = new Stack<string>(); public string Condition() { string condition = string.Concat(this._StringStack.ToArray()); this._StringStack.Clear(); return condition; } // 解析 二元表達式 類型 protected override Expression VisitBinary(BinaryExpression node) { if (node == null) throw new ArgumentNullException("BinaryExpression"); this._StringStack.Push(")"); base.Visit(node.Right);//解析右邊 this._StringStack.Push(" " + node.NodeType.ToSqlOperator() + " "); base.Visit(node.Left);//解析左邊 this._StringStack.Push("("); return node; } // 解析 屬性表達式 類型 protected override Expression VisitMember(MemberExpression node) { if (node == null) throw new ArgumentNullException("MemberExpression"); this._StringStack.Push(" [" + node.Member.Name + "] "); return node; } // 解析 常量表達式 類型 protected override Expression VisitConstant(ConstantExpression node) { if (node == null) throw new ArgumentNullException("ConstantExpression"); this._StringStack.Push(node.Value.ToString()); return node; } // 解析 方法表達式 類型 protected override Expression VisitMethodCall(MethodCallExpression m) { if (m == null) throw new ArgumentNullException("MethodCallExpression"); string format; switch (m.Method.Name) { case "StartsWith": format = "({0} LIKE '{1}%')"; break; case "Contains": format = "({0} LIKE '%{1}%')"; break; case "EndsWith": format = "({0} LIKE '%{1}')"; break; default: throw new NotSupportedException(m.NodeType + " is not supported!"); } this.Visit(m.Object); this.Visit(m.Arguments[0]); string right = this._StringStack.Pop(); string left = this._StringStack.Pop(); this._StringStack.Push(String.Format(format, left, right)); return m; } } }
調用執行
using System; using System.Linq.Expressions; namespace e2 { class Program { static void Main(string[] args) { Test1(); } static void Test1() { Expression<Func<User, bool>> expression = (u) => u.age > 1; expression = expression.And(x=>x.uid>2); expression = expression.Or(x=>x.uid>2); expression = expression.Not(); ConditionBuilderVisitor visitor = new ConditionBuilderVisitor(); var exp = visitor.Visit(expression); Console.WriteLine(visitor.Condition()); } } public class User { public int uid { get; set; } public int age { get; set; } public string name { get; set; } } }
場景;DTO
類轉換爲 Model
類
方案一:手動,硬編碼,不易出錯,效率高,但太繁瑣
[HttpPost] public IActionResult Sava(UserDTD dtd) { User user = new User { uid = dtd.id, uname = dtd.name }; _userBll.Sava(user); }
方案二:使用反射,損耗高,兩個類型的屬性類型和名稱需保證一致
/// <summary> /// 反射映射 /// </summary> public class ReflectionMapper { /// <summary> /// 實體轉換 /// </summary> /// <typeparam name="T">傳入類型</typeparam> /// <typeparam name="TResult">返回值類型</typeparam> /// <param name="tIn">傳入參數</param> /// <returns>轉換好的實體</returns> public static TResult Trans<T, TResult>(T tIn) { TResult tOut = Activator.CreateInstance<TResult>(); 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; } }
方案三:序列化反序列化,損耗高,兩個類型的屬性類型和名稱需保證一致
/// <summary> /// 使用第三方序列化反序列化工具 /// </summary> public class SerializeMapper { /// <summary> /// 實體轉換 /// </summary> public static TResult Trans<T, TResult>(T tIn) { return JsonConvert.DeserializeObject<TResult>(JsonConvert.SerializeObject(tIn)); } }
方案四:表達式目錄樹 + 字典緩存
/// <summary> /// 生成表達式目錄樹 字典緩存 /// </summary> public class ExpressionMapper { /// <summary> /// 字典緩存--hash分佈 /// </summary> private static Dictionary<string, object> _dic = new Dictionary<string, object>(); /// <summary> /// 實體轉換 /// </summary> public static TResult Trans<T, TResult>(T tIn) { string key = string.Format("funckey_{0}_{1}", typeof(T).FullName, typeof(TResult).FullName); if (!_dic.ContainsKey(key)) { ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p"); List<MemberBinding> memberBindingList = new List<MemberBinding>(); foreach (var item in typeof(TResult).GetProperties()) { MemberExpression property = Expression.Property(parameterExpression, typeof(T).GetProperty(item.Name)); MemberBinding memberBinding = Expression.Bind(item, property); memberBindingList.Add(memberBinding); } foreach (var item in typeof(TResult).GetFields()) { MemberExpression property = Expression.Field(parameterExpression, typeof(T).GetField(item.Name)); MemberBinding memberBinding = Expression.Bind(item, property); memberBindingList.Add(memberBinding); } MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TResult)), memberBindingList.ToArray()); Expression<Func<T, TResult>> lambda = Expression.Lambda<Func<T, TResult>>(memberInitExpression, new ParameterExpression[] { parameterExpression }); Func<T, TResult> func = lambda.Compile(); //調用Compile方法將表達式轉換成委託 _dic[key] = func; //拼裝是一次性的 } return ((Func<T, TResult>)_dic[key]).Invoke(tIn); } }
方案五:表達式目錄樹 + 泛型緩存(泛型緩存特色:爲不一樣類型的組合去緩存一個結果)
/// <summary> /// 生成表達式目錄樹 泛型緩存 /// </summary> /// <typeparam name="T">傳入參數類型</typeparam> /// <typeparam name="TResult">返回值類型</typeparam> public class ExpressionGenericMapper<T, TResult> { /// <summary> /// 泛型緩存 /// </summary> private static Func<T, TResult> _func = null; /// <summary> /// 靜態構造函數(只會被調用一次) /// </summary> static ExpressionGenericMapper() { ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p"); List<MemberBinding> memberBindingList = new List<MemberBinding>(); foreach (var item in typeof(TResult).GetProperties()) { MemberExpression property = Expression.Property(parameterExpression, typeof(T).GetProperty(item.Name)); MemberBinding memberBinding = Expression.Bind(item, property); memberBindingList.Add(memberBinding); } foreach (var item in typeof(TResult).GetFields()) { MemberExpression property = Expression.Field(parameterExpression, typeof(T).GetField(item.Name)); MemberBinding memberBinding = Expression.Bind(item, property); memberBindingList.Add(memberBinding); } MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TResult)), memberBindingList.ToArray()); Expression<Func<T, TResult>> lambda = Expression.Lambda<Func<T, TResult>>(memberInitExpression, new ParameterExpression[] { parameterExpression }); _func = lambda.Compile();//拼裝是一次性的 } /// <summary> /// 實體轉換 /// </summary> public static TResult Trans(T t) { return _func(t); } }
經過反編譯工具得知,Lambda
表達式,其實就是一個方法,在中間語言中,爲其分配了一個方法名稱(<>
)
注意事項
this
關鍵字,不能有任何其餘修飾符(out/ref
)編譯結果
public static class Extend { public static int ToInt(this int? k) { return k ?? 0; } }
.class public auto ansi abstract sealed beforefieldinit lq1.Extend extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Methods .method public hidebysig static int32 ToInt ( valuetype [mscorlib]System.Nullable`1<int32> k ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x216c // Code size 13 (0xd) .maxstack 1 .locals init ( [0] int32 ) IL_0000: nop IL_0001: ldarga.s k IL_0003: call instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault() IL_0008: stloc.0 IL_0009: br.s IL_000b IL_000b: ldloc.0 IL_000c: ret } // end of method Extend::ToInt } // end of class lq1.Extend
linq to object
聲明的方法在 Enumerable
類中,針對於 Enumerable
進行處理,數據來以內存數據
操做的表達式是一個委託
inq to sql
聲明的方法在 Queryable
類中,針對於 Queryable
進行處理,數據來以內存數據或來自數據庫的的數據源
操做的表達式是一個表達式目錄樹,經過表達式目錄樹解析成SQL
語句
yield
迭代器using System; using System.Collections.Generic; namespace lq2 { class Program { static void Main(string[] args) { List<User> list = new List<User> { new User(){uid=1,uname="a1",age=18,gender=0 }, new User(){uid=2,uname="a2",age=28,gender=1 }, new User(){uid=3,uname="a3",age=23,gender=1 }, new User(){uid=4,uname="a4",age=18,gender=0 }, new User(){uid=5,uname="a5",age=33,gender=1 } }; var d1 = list.MyWhere(x => x.uid > 3); foreach (var item in d1) { Console.WriteLine(item.uid); } } } public class User { public int uid { get; set; } public int age { get; set; } public string uname { get; set; } public int gender { get; set; } } public static class Extend { public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> rouse, Func<T, bool> func) { foreach (var item in rouse) { if (func(item)) { // yield 迭代器一般與 Enumerable共同使用,實現按需獲取(延遲加載) yield return item; } } } } }
Expression
通常都是都是配合委託一塊兒來使用的,好比和委託Action
,Func
Expression<Func<T>>
是能夠轉成Func
的(經過compile()
方法轉換),反之則不行
日常項目中常常用到的EF
操做時的擴展方法(Where
之類的)其實傳的就是表達式目錄樹