C#的λ表达式树学习
lambda 表达式树
可执行代码
Lambda表达式不仅可以用来创建委托实例,C#编译器也能够将他们转换成表达式树
(Lambda语句)
(Lambda表达式)
λ表达式树也是代码,我们把它当成另外一种动态语言学习就好了
λ表达式树最终的本质就是一个方法的编译状态
expression==(express.lambda)> lambda表达式树 ==(compile)》func委托
lambda, compile
表达式树 ,他的初始化是
Expression.Convert即等价于Convert静态类
将表达式树生成一个 委托(
Expression 提供了一种相对高级的抽象,允许你以更直观的方式创建和操作代码逻辑。它通常用于构建 LINQ 查询、动态生成委托等高级场景。
表达式树通常用于动态创建代码、代码分析、LINQ 查询等场景,而不是用于创建类。可以使用 Expression 类动态地创建 lambda 表达式,而这个 lambda 表达式可以用于创建新对象。但是,这个对象的类型通常是在编译时已知的,而不是在运行时动态创建的。
C#的λ表达式树(LambdaExpression)保姆级超详细简单入门教程 - 知乎 (zhihu.com)
通过Expression表达式树,为EF Core找回AddOrUpdate方法 - 知乎 (zhihu.com)
Masuit.Tools/Masuit.Tools.AspNetCore/AspNetCore/DbSetExtensions.cs at 382dc96506ac6ac87976332740053d313bd6f27b · ldqk/Masuit.Tools (github.com)
/// <summary>
/// 添加或更新
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey">按哪个字段更新</typeparam>
/// <param name="dbSet"></param>
/// <param name="keySelector">按哪个字段更新</param>
/// <param name="entity"></param>
public static void AddOrUpdate<T, TKey>(this DbSet<T> dbSet, Expression<Func<T, TKey>> keySelector, T entity) where T : class
{
if (keySelector == null)
{
throw new ArgumentNullException(nameof(keySelector));
}
if (entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
var keyObject = keySelector.Compile()(entity);
var parameter = Expression.Parameter(typeof(T), "p");
var lambda = Expression.Lambda<Func<T, bool>>(Expression.Equal(ReplaceParameter(keySelector.Body, parameter), Expression.Constant(keyObject)), parameter);
var item = dbSet.FirstOrDefault(lambda);
if (item == null)
{
dbSet.Add(entity);
}
else
{
// 获取主键字段
var dataType = typeof(T);
var keyFields = dataType.GetProperties().Where(p => p.GetCustomAttribute<KeyAttribute>() != null).ToList();
if (!keyFields.Any())
{
string idName = dataType.Name + "Id";
keyFields = dataType.GetProperties().Where(p => p.Name.Equals("Id", StringComparison.OrdinalIgnoreCase) || p.Name.Equals(idName, StringComparison.OrdinalIgnoreCase)).ToList();
}
// 更新所有非主键属性
foreach (var p in typeof(T).GetProperties().Where(p => p.GetSetMethod() != null && p.GetGetMethod() != null))
{
// 忽略主键
if (keyFields.Any(x => x.Name == p.Name))
{
continue;
}
var existingValue = p.GetValue(entity);
if (p.GetValue(item) != existingValue)
{
p.SetValue(item, existingValue);
}
}
foreach (var idField in keyFields.Where(p => p.GetSetMethod() != null && p.GetGetMethod() != null))
{
var existingValue = idField.GetValue(item);
if (idField.GetValue(entity) != existingValue)
{
idField.SetValue(entity, existingValue);
}
}
}
}
private static Expression ReplaceParameter(Expression oldExpression, ParameterExpression newParameter)
{
return oldExpression.NodeType switch
{
ExpressionType.MemberAccess => Expression.MakeMemberAccess(newParameter, ((MemberExpression)oldExpression).Member),
ExpressionType.New => Expression.New(((NewExpression)oldExpression).Constructor, ((NewExpression)oldExpression).Arguments.Select(a => ReplaceParameter(a, newParameter)).ToArray()),
_ => throw new NotSupportedException("不支持的表达式类型:" + oldExpression.NodeType)
};
}

浙公网安备 33010602011771号