Expression
大约 8 分钟约 2294 字
Expression
表达式目录树的本质、特点、和委托的区别
Expression<Func<People, bool>> expression = p => p.Id == 10;//可以使用lambda表达式声明
Func<People, bool> func = expression.Compile();
bool bResult = func.Invoke(new People()
{
Id = 10,
Name = "Richard"
});
Func<int, int, int> func = (m, n) =>
{
int i = 0;
return m * n + 2;
};
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2; //快捷声明--使用lambad表达式来声明
var erpPlu = exp.Compile();//表达式目录树可以通过compile 转换成一个委托
动态拼装Expression
{
//表达式目录树的拼装---最基础版本
Expression<Func<int>> expression = () => 123 + 234; //没有参数,返回int
ConstantExpression expression1 = Expression.Constant(123); //常量表达式
ConstantExpression expression2 = Expression.Constant(234); //常量表达式
//二元表达式
BinaryExpression binaryExpression = Expression.Add(expression1, expression2);
Expression<Func<int>> expressionReslut = Expression.Lambda<Func<int>>(binaryExpression);
Func<int> func = expressionReslut.Compile();
int iResult = func.Invoke();
}
{
//表达式目录树的拼装---带参数版本
Expression<Func<int, int>> expression1 = m => m + 1;
Func<int, int> func = expression1.Compile();
int iResult = func.Invoke(5);
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "m");
ConstantExpression constant = Expression.Constant(1, typeof(int));
BinaryExpression addExpression = Expression.Add(parameterExpression, constant);
Expression<Func<int, int>> expression = Expression.Lambda<Func<int, int>>(addExpression, new ParameterExpression[1]
{
parameterExpression
});
Func<int, int> func1 = expression.Compile();
int iResult1 = func1.Invoke(5);
}
{
//表达式目录树的拼装---带有多个参数的
Expression<Func<int, int, int>> expression = (m, n) => m * n + 2;
Func<int, int, int> func = expression.Compile();
int iResult = func.Invoke(10, 20);
ParameterExpression parameterExpressionM = Expression.Parameter(typeof(int), "m");
ParameterExpression parameterExpressionN = Expression.Parameter(typeof(int), "n");
BinaryExpression multiply = Expression.Multiply(parameterExpressionM, parameterExpressionN);
ConstantExpression constantExpression = Expression.Constant(2);
BinaryExpression plus = Expression.Add(multiply, constantExpression);
Expression<Func<int, int, int>> expression1 = Expression.Lambda<Func<int, int, int>>(plus, new ParameterExpression[2]
{
parameterExpressionM,
parameterExpressionN
});
Func<int, int, int> func1 = expression1.Compile();
int iResult1 = func1.Invoke(10, 20);
}
{
{
IQueryable<People> peoplesQueyrabable = new List<People>().AsQueryable();
Expression<Func<People, bool>> predicate = c => c.Id == 10;
var query = peoplesQueyrabable.Where(predicate); //Expression<Func<TSource, bool>> predicate
}
//表达式目录树的拼装---高级篇
//类似于这种比较复杂的:建议大家可以反编译看看
//1.把这个快捷声明的表达式目录树,复制到一个单独的类,为了方便反编译查看中间语言
//2.反编译看中间语言
{
{
Expression<Func<People, bool>> predicate = c => c.Id == 10;
Func<People, bool> func = predicate.Compile();
bool bResult = func.Invoke(new People()
{
Id = 10
});
//1.声明一个变量C;
ParameterExpression parameterExpression = Expression.Parameter(typeof(People), "c");
//2.c.id,调用c.的属性---people的属性id,先获取属性
//a.获取属性--反射
FieldInfo fieldId = typeof(People).GetField("Id"); //id
//b.c.Id 通过parameterExpression来获取 调用Id
MemberExpression idExp = Expression.Field(parameterExpression, fieldId);
//3.== Equeals 是个方法 ,是id的方法,id 是int类型,应该获取int 的 ===
ConstantExpression constant10 = Expression.Constant(10, typeof(int));
//c.id==10;
Expression expressionExp = Expression.Equal(idExp, constant10);
Expression<Func<People, bool>> predicate1 = Expression.Lambda<Func<People, bool>>(expressionExp, new ParameterExpression[1]
{
parameterExpression
});
Func<People, bool> func1 = predicate1.Compile();
bool bResult1 = func1.Invoke(new People()
{
Id = 10
});
}
//表达式目录树的拼装---超级篇
//如果遇到很长的表达式目录树--拼装建议从右往左拼装
{
Expression<Func<People, bool>> predicate = c =>
c.Id.ToString() == "10"
&& c.Name.Equals("Richard")
&& c.Age > 35;
Func<People, bool> func = predicate.Compile();
bool bResult = func.Invoke(new People()
{
Id = 10,
Name = "Richard",
Age = 36
});
Console.WriteLine("****************************************************");
//1.拼装c.Age > 35;
ParameterExpression parameterExpression = Expression.Parameter(typeof(People), "c");
ConstantExpression constant35 = Expression.Constant(35);
//age
PropertyInfo propAge = typeof(People).GetProperty("Age");
//c.Age
var ageExp = Expression.Property(parameterExpression, propAge);
//c.Age > 35
var cagExp = Expression.GreaterThan(ageExp, constant35);
Console.WriteLine("****************************************************");
//拼装:c.Name.Equals("Richard")
//字符串Richard
ConstantExpression constantrichard = Expression.Constant("Richard");
// Name属性
PropertyInfo propName = typeof(People).GetProperty("Name");
//c.Name
var nameExp = Expression.Property(parameterExpression, propName);
//获取equals方法
MethodInfo equals = typeof(string).GetMethod("Equals", new Type[] { typeof(string) });
//c.Name.Equals("Richard")
var NameExp = Expression.Call(nameExp, equals, constantrichard);
Console.WriteLine("****************************************************");
//拼装:c.Id.ToString() == "10"
ConstantExpression constantExpression10 = Expression.Constant("10", typeof(string));
//id
FieldInfo fieldId = typeof(People).GetField("Id");
//c.Id
var idExp = Expression.Field(parameterExpression, fieldId);
//获取ToString
MethodInfo toString = typeof(int).GetMethod("ToString", new Type[0]);
//c.Id.ToString(); Expression.Call:调用方法
var toStringExp = Expression.Call(idExp, toString, Array.Empty<Expression>());
// c.Id.ToString()=="10"
var EqualExp = Expression.Equal(toStringExp, constantExpression10);
Console.WriteLine("****************************************************");
//c.Id.ToString() == "10"&&c.Name.Equals("Richard")
var plus = Expression.AndAlso(EqualExp, NameExp);
//c.Id.ToString() == "10"&&c.Name.Equals("Richard") && c.Age > 35
var exp = Expression.AndAlso(plus, cagExp);
Expression<Func<People, bool>> predicate1 = Expression.Lambda<Func<People, bool>>(exp, new ParameterExpression[1]
{
parameterExpression
});
Func<People, bool> func1 = predicate1.Compile();
bool bResult1 = func1.Invoke(new People()
{
Id = 10,
Name = "Richard",
Age = 36
});
}
}
}
为什么要这样拼
{
//SELECT* FROM USER WHERE name like "" and age=10;
//在之前,数据库查询基本都是拼接Sql语句;
//以前根据用户输入拼装条件
string sql = "SELECT * FROM USER WHERE 1=1";
Console.WriteLine("用户输入个名称,为空就跳过");
string name = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(name))
{
sql += $" and name like '%{name}%'";
}
Console.WriteLine("用户输入个账号,为空就跳过");
string account = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(account))
{
sql += $" and account like '%{account}%'";
}
}
//现在主流的是Linq:---通过条件拼装的一个很长的表达式目录树;到数据库执行的时候;数据库能够认识表达式目录树吗? 当然不认识; 数据库只认识Sql语句; 需要把表达式目录树如进行拆解;组装成一个Sql语句的条件
{
{
//来自于数据库的数据
var dbSet = new List<People>().AsQueryable();
var result = dbSet.Where(p => p.Age == 25 & p.Name.Contains("阳光下的微笑"));
//Expression<Func<People, bool>> predicate = p => p.Age == 25 & p.Name.Contains("阳光下的微笑");
Expression<Func<People, bool>> exp = null;
Console.WriteLine("用户输入个名称,为空就跳过");
string name = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(name))
{
exp = p => p.Name.Contains(name);
}
Console.WriteLine("用户输入个最小年纪,为空就跳过");
string age = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(age) && int.TryParse(age, out int iAge))
{
exp = p => p.Age > iAge;
}
//如果name 和age 都不为空呢?
//遇到这种我们应该怎么做? 就可以把一整条表达式目录树做拼装;
//1.代码量多:----封装;
//如果封装一个类库---可以拼装的过程,给封装装起来;提供几个方法;只需要把满足条件的小结构表达式传入;
//不断的调用;拼接的表达式目录树,就越来长?
//动态的拼装查询条件!
}
}
案例
public static void MapperTest()
{
//需求. 需要把People PeopleCopy:
//1.反射
//2.序列化
//3.Automapper
//4.可以直接new一个对象
//5.硬编码
{
//People people = new People()
//{
// Id = 11,
// Name = "剑锋",
// Age = 31
//};
////PeopleCopy people1= (PeopleCopy)people; //不能转换? 没有继承关系
////a: 方法一
//PeopleCopy peopleCopy0 = new PeopleCopy()
//{
// Id = people.Id,
// Name = people.Name,
// Age = people.Age
//};
////b:方法二
//PeopleCopy peopleCopy1 = ReflectionMapper.Trans<People, PeopleCopy>(people);
////c:方法三
//PeopleCopy peopleCopy2 = SerializeMapper.Trans<People, PeopleCopy>(people);
////这样好不好?
////以上三种方式不好:第一种方式:性能好,不灵活;不能共用;如果换成其他的类型就不能用了;
//// 第二、三种方式;灵活,但是性能不好!
////三种,总是有不完美的地儿;
////动态拼装转换过程;动态拼装了硬编码;
////d:方法四 支持泛型版本:就可以支持多种类型
//PeopleCopy peopleCopy3 = ExpressionMapper.Trans<People, PeopleCopy>(people);
////peopleCopy3 通过普通缓存+字典缓存; 第一次生成的时候,保存一个委托在缓存中,如果第二次来,委托就可以直接从缓存中获取到,直接使用;---直接运行委托;直接运行硬编码;---效率高;
////泛型缓存:就是为不同的类型生成副本:为每一组类型的组合,生成一个副本;
////e:方法五:性能最高的: 支持泛型版本:就可以支持多种类型
////泛型缓存+动态拼装表达式目录树(拼装了执行的动作--编码-拼装了执行逻辑--在代码运行的时候,动态的生成逻辑);动态的生成硬编码;
//PeopleCopy peopleCopy4 = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);
//{
// //能不能把People变成PeopleCopy的过程封装在一个委托中;
// Func<People, PeopleCopy> func = p => new PeopleCopy
// {
// Id = p.Id,
// Name = p.Name,
// Age = p.Age
// };
// PeopleCopy peopleCopynew = func.Invoke(people);
// //如果能够把这个委托给缓存起来;根据我们的诉求,缓存一个委托;委托哪儿来?委托其实可以通过表达式目录树Compile一下,就可以得到一个委托;如果拼装一个表达式目录树,再Compile一下,然后缓存起来;就相当于拼装了这一组的转换逻辑;
// //拼装一下后,缓存下来,如果后面再需要使用,就可以直接使用这个委托了;
//}
//动态的生生硬编码:还有什么技术可以实现?
}
{
People people = new People()
{
Id = 11,
Name = "Richard",
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 < 1_000_000; 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 < 1_000_000; i++)
{
PeopleCopy peopleCopy = ReflectionMapper.Trans<People, PeopleCopy>(people);
}
watch.Stop();
reflection = watch.ElapsedMilliseconds;
}
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 1_000_000; i++)
{
PeopleCopy peopleCopy = SerializeMapper.Trans<People, PeopleCopy>(people);
}
watch.Stop();
serialize = watch.ElapsedMilliseconds;
}
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 1_000_000; i++)
{
PeopleCopy peopleCopy = ExpressionMapper.Trans<People, PeopleCopy>(people);
}
watch.Stop();
cache = watch.ElapsedMilliseconds;
}
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 1_000_000; 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"); //性能好,而且扩展性也好===又要马儿跑,又要马儿不吃草。。。
}
}