目录
一、Expression概念
表达式目录树,只能一行,不可用花括号
目的: 将C#语句转化成SQL语句,隔离数据库,让开发人员无需为不同的数据库而发愁
ExpressionVisitor 递归获取每个表达式的值,然后在进行拼装,
即:先拆一遍,再每个元素拼装一遍,整个过程是递归两遍
Expression解析表达式,是用Expression的拆的一部分
Expression链接表达式,是用Expression的合的一部分
两者各是整个过程的一半,谨慎合并使用
二、Expression基础调用
前期准备:
public static int GetSum(int x)
{
return x + 1;
}
1、简略版
代码编写:
//传入一行的Lambda表达式
Expression<Func<int, bool>> exp = (x) => (x + GetSum(x)).Equals(7);
//表达式调用
Console.WriteLine(exp.Compile().Invoke(3));
2、完整版
代码编写:
//入参x配置
ParameterExpression _x = Expression.Parameter(typeof(int), "x");
//GetSum 获取
MethodInfo getSum = typeof(Program).GetMethod("GetSum");
//GetSum(x) 配置
MethodCallExpression getSum_x = Expression.Call(null, getSum, _x);
//(x + GetSum(x)) 配置
BinaryExpression callLeft = Expression.Add(_x, getSum_x);
//Equals方法配置
MethodInfo equals = typeof(Int32).GetMethod("Equals", new[] { typeof(Int32) });
//7 配置
ConstantExpression _7 = Expression.Constant(7, typeof(int));
//(x + GetSum(x)).Equals(7) 配置
MethodCallExpression callAll = Expression.Call(callLeft, equals, _7);
//整体组合
Expression<Func<int, bool>> exp1 =
Expression.Lambda<Func<int, bool>>(callAll,
new ParameterExpression[1] { _x });
//调用
Console.WriteLine(exp1.Compile()(3));
//---------------------------------------------------------------------------------------------------------------------------------------
如何快速获取完整版:通过ILSpy反编译简单语句获取。
若无法得到,可参考 http://t.csdn.cn/hsuVq
注:在ILSpy中 (MethodInfo)MethodBase.GetMethodFromHandle(RuntimeMethodHandle) 要进行手动配置
//GetSum 获取
MethodInfo getSum1 = typeof(Program).GetMethod("GetSum");
// (MethodInfo)MethodBase.GetMethodFromHandle(RuntimeMethodHandle)
//Equals方法配置
MethodInfo equals1 = typeof(Int32).GetMethod("Equals", new[] { typeof(Int32) });
//(MethodInfo)MethodBase.GetMethodFromHandle(RuntimeMethodHandle)
三、Expression应用 -- 复制相同类
前期准备:
People Tom = new People { _id = 1, _name = "Tom", _age = 18 };
class People
{
public int _id;
public string _name;
public int _age;
}
class NewPeople
{
public int _id;
public string _name;
public int _age;
}
方法一:硬编码
代码编写:
NewPeople TomNew_1 = new NewPeople
{
_id = Tom._id,
_name = Tom._name,
_age = Tom._age
};
方法二:反射
代码编写:
NewPeople TomNew_2 = Copy(Tom);
public static NewPeople Copy(People Tom)
{
NewPeople TomNew = Activator.CreateInstance<NewPeople>();
foreach (var item in Tom.GetType().GetFields())
{
TomNew.GetType().GetField(item.Name).SetValue(TomNew, item.GetValue(Tom));
}
return TomNew;
}
方法三:序列化
代码编写:
var TomNew_3 = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(Tom));
方法四:表达式目录树_Method
代码解析:转换代码写成Expression形式,保存至字典中,二次调用时,通过key直接调用Expression表达式
代码编写:
NewPeople TomNew_4 = Trans<People, NewPeople>(Tom);
private static Dictionary<string, object> _Dic = new Dictionary<string, object>();
public static TOut Trans<TIn, TOut>(TIn Tom)
{
string key = string.Format($"funckey_{typeof(TIn).FullName}_{typeof(TOut).FullName}");
if (!_Dic.ContainsKey(key)) //若没有key
{
//入参
ParameterExpression param = Expression.Parameter(typeof(TIn), "x");
//成员列表
List<MemberBinding> memberBindings = new List<MemberBinding>();
//遍历字段
foreach (FieldInfo item in typeof(TOut).GetFields())
{
var field = Expression.Field(param, typeof(TIn).GetField(item.Name));
MemberBinding memberBinding = Expression.Bind(item, field);
memberBindings.Add(memberBinding);
}
MemberInitExpression memberInit = Expression.MemberInit(
Expression.New(typeof(NewPeople)),
memberBindings.ToArray());
Expression<Func<TIn, TOut>> ELambda = Expression.Lambda<Func<TIn, TOut>>(memberInit,
new ParameterExpression[1] { param });
_Dic[key] = ELambda.Compile();
}
return ((Func<TIn, TOut>)_Dic[key]).Invoke(Tom);
方法五:表达式目录树_Class -- 推荐(最快)
代码解析:初次调用时,转换代码写成Expression形式,二次调用时,通过类名直接获取Expression表达式
注:静态构造方法的使用
代码编写:
var TomNew_5 = ExpressionTrans<People, NewPeople>.Trans(Tom);
class ExpressionTrans<TIn, TOut>
{
private static Func<TIn, TOut> _Fun = null;
static ExpressionTrans()
{
//入参
ParameterExpression param = Expression.Parameter(typeof(TIn), "x");
//成员列表
List<MemberBinding> memberBindings = new List<MemberBinding>();
//遍历字段
foreach (FieldInfo item in typeof(TOut).GetFields())
{
var field = Expression.Field(param, typeof(TIn).GetField(item.Name));
MemberBinding memberBinding = Expression.Bind(item, field);
memberBindings.Add(memberBinding);
}
MemberInitExpression memberInit = Expression.MemberInit(
Expression.New(typeof(NewPeople)),
memberBindings.ToArray());
Expression<Func<TIn, TOut>> ELambda = Expression.Lambda<Func<TIn, TOut>>(memberInit,
new ParameterExpression[1] { param });
_Fun = ELambda.Compile();
}
public static TOut Trans(TIn Tom)
{
return _Fun.Invoke(Tom);
}
}
四、ExpressionVisitor解析
前期准备:
class People
{
public int Id { get; set; }
public int Age { get; set; }
}
//------------------------------------------------------------------
/// <summary>
/// 表达式条件建筑类
/// </summary>
class ConditionBuilderVisitor : ExpressionVisitor
{
/// <summary>
/// 栈:先进后出
/// </summary>
private Stack<string> _stack = new Stack<string>();
/// <summary>
/// 栈转字符串
/// </summary>
public string Condition()
{
string condition = string.Concat(this._stack.ToArray());
this._stack.Clear();
return condition;
}
/// <summary>
/// 二元表达式压入
/// </summary>
protected override Expression VisitBinary(BinaryExpression node)
{
if (node == null) throw new ArgumentException("BinaryExpression");
this._stack.Push(")");
base.Visit(node.Right); //解析右边
this._stack.Push(" " + node.NodeType.ToSqlOperator() + " ");
base.Visit(node.Left); //解析左边
this._stack.Push("(");
return node;
}
/// <summary>
/// 元素压入
/// </summary>
protected override Expression VisitMember(MemberExpression node)
{
if (node == null) throw new ArgumentException("MemberExpression");
this._stack.Push($"[{node.Member.Name}]");
return node;
}
/// <summary>
/// 常数压入
/// </summary>
protected override Expression VisitConstant(ConstantExpression node)
{
if (node == null) throw new ArgumentException("ConstantExpression");
//压入常数
this._stack.Push($"'{node.Value.ToString()}'");
return node;
}
}
//---------------------------添加扩展方法----------------------------------
static class ExpressionVisitorExtend
{
/// <summary>
/// 类型转字符
/// </summary>
internal static string ToSqlOperator(this ExpressionType type)
{
switch (type)
{
case ExpressionType.Add:
return "+";
case ExpressionType.Subtract:
return "-";
case ExpressionType.Multiply:
return "*";
case ExpressionType.Divide:
return "/";
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("不支持该方法");
}
}
代码编写:
internal class Program
{
static void Main(string[] args)
{
Expression<Func<People, int>> exp = (x) => x._Id + 5 + 4 - 6;
ConditionBuilderVisitor conditional = new ConditionBuilderVisitor();
conditional.Visit(exp);
string result = conditional.Condition();
Console.WriteLine(result); //结果显示:((([_Id] + '5') + '4') - '6')
}
}
五、ExpressionVisitor合并
前期准备:
class People
{
public int _Id { set; get; }
public int _Age { set; get; }
}
//-------------------------------- 入参统一 ------------------------------
internal class NewExpressionVisitor : ExpressionVisitor
{
public ParameterExpression _NewParameter { get; private set; }
public NewExpressionVisitor(ParameterExpression newParameter)
{
_NewParameter = newParameter;
}
/// <summary>
/// 入参设定
/// </summary>
protected override Expression VisitParameter(ParameterExpression node)
{
return this._NewParameter;
}
}
//-----------------------------------扩展方法-----------------------------
static class ExpressionVisitorExtend
{
/// <summary>
/// 与和或的父方法
/// </summary>
private static Expression<Func<T, bool>> AndOr<T>(this Expression<Func<T, bool>> exp1,
Expression<Func<T, bool>> exp2,
Func<Expression, Expression, BinaryExpression> func)
{
ParameterExpression newParameter = Expression.Parameter(typeof(T), "x");
NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
var left = visitor.Visit(exp1.Body);
var right = visitor.Visit(exp2.Body);
var body = func(left, right);
return Expression.Lambda<Func<T, bool>>(body, newParameter);
}
/// <summary>
/// 两个条件 -- 与运算
/// </summary>
internal static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> exp1,
Expression<Func<T, bool>> exp2)
{
return AndOr(exp1, exp2, Expression.And);
}
/// <summary>
/// 两个条件 -- 或运算
/// </summary>
internal static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> exp1,
Expression<Func<T, bool>> exp2)
{
return AndOr(exp1, exp2, Expression.Or);
}
/// <summary>
/// 两个条件 -- 非运算
/// </summary>
internal static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> exp)
{
var parameter = exp.Parameters[0];
var body = Expression.Not(exp.Body);
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
}
代码编写:
internal class Program
{
static void Main(string[] args)
{
List<People> peoples = new List<People>()
{
new People(){ _Id = 1000,_Age = 20},
new People(){ _Id = 500,_Age = 21},
new People(){ _Id = 640,_Age = 25},
new People(){ _Id = 2300,_Age = 28}
};
Expression<Func<People, bool>> exp1 = (x) => x._Age > 18;
Expression<Func<People, bool>> exp2 = (y) => y._Id > 700;
//获取表达式
var result = exp1.And(exp2);
//调用获取结果
var list = peoples.Where(result.Compile()).ToList();
//result结果:x => ((x._Age > 18) And (x._Id > 700))
Console.WriteLine(result);
}
}
如有错误,烦请批评指正