06-C#.Net-表达式目录树-学习笔记

2021-06-26 .NET高级班 72-ASP.NET Core Hangfire任务调度的使用 一:控制台应用 1.首先nuget引入 Hangfire.core Hangfire.SqlServer 2.具体使用代码 static void Main(string[] args) { try { //1.nuget引入:Hangfire.core // Hangfire.SqlServer GlobalConfiguration.Configuration .SetDataCompati 阅读详情

一、本质与核心概念

表达式目录树是一种数据结构,以树形结构描述代码逻辑。它不是可执行代码,而是对代码结构的描述。

  • 委托(Delegate):编译后直接生成 IL,可以直接执行
  • 表达式目录树(Expression Tree):是一个树形数据对象,描述了计算关系,不能直接执行
  • Expression<Func<T>> vs Func<T>:前者是表达式树,后者是委托,二者可通过 .Compile() 单向转换
  • 语法限制:表达式目录树只能是单行 Lambda,不能有大括号和多行语句
  • 树形结构:类似二叉树,每个节点都是一个子表达式,可以一层层拆解或拼装
// 委托:直接可执行
Func<int, int, int> func = (m, n) => m * n + 2;

// 表达式目录树:描述结构,需要 Compile() 后才能执行
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;
Func<int, int, int> compiled = exp.Compile();
int result = compiled(10, 20); // 202

表达式 (m, n) => m * n + 2 的树形结构:

+(加法)
       / \
      *   2(常量)
     / \
    m   n(参数)

二、动态拼装表达式目录树

拼装的核心思路:把最小粒度的节点逐步组合成完整表达式,最后包裹成 Lambda。

2.1 基础:无参数

// 目标:() => 123 + 234
ConstantExpression c1 = Expression.Constant(123);
ConstantExpression c2 = Expression.Constant(234);
BinaryExpression add = Expression.Add(c1, c2);
Expression<Func<int>> lambda = Expression.Lambda<Func<int>>(add);
int result = lambda.Compile()(); // 357

2.2 带参数

// 目标:m => m + 1
ParameterExpression paramM = Expression.Parameter(typeof(int), "m");
ConstantExpression c1 = Expression.Constant(1);
BinaryExpression add = Expression.Add(paramM, c1);
Expression<Func<int, int>> lambda = Expression.Lambda<Func<int, int>>(add, paramM);
int result = lambda.Compile()(5); // 6

2.3 访问属性/字段

// 目标:c => c.Id == 10
ParameterExpression paramC = Expression.Parameter(typeof(People), "c");

// 字段用 Expression.Field,属性用 Expression.Property
FieldInfo fieldId = typeof(People).GetField("Id");
MemberExpression idExp = Expression.Field(paramC, fieldId);

ConstantExpression c10 = Expression.Constant(10);
BinaryExpression equal = Expression.Equal(idExp, c10);

Expression<Func<People, bool>> lambda =
    Expression.Lambda<Func<People, bool>>(equal, paramC);

2.4 调用方法

// 目标:c => c.Name.Equals("Richard")
ParameterExpression paramC = Expression.Parameter(typeof(People), "c");
PropertyInfo propName = typeof(People).GetProperty("Name");
MemberExpression nameExp = Expression.Property(paramC, propName);

MethodInfo equalsMethod = typeof(string).GetMethod("Equals", new[] { typeof(string) });
ConstantExpression constRichard = Expression.Constant("Richard");

MethodCallExpression callExp = Expression.Call(nameExp, equalsMethod, constRichard);

// 包装成 Lambda 并执行
Expression<Func<People, bool>> lambda =
    Expression.Lambda<Func<People, bool>>(callExp, paramC);
bool result = lambda.Compile()(new People { Name = "Richard" }); // true

2.5 复杂表达式:建议从右往左拼装

// 目标:c => c.Id.ToString() == "10" && c.Name.Equals("Richard") && c.Age > 35

ParameterExpression paramC = Expression.Parameter(typeof(People), "c");

// 1. c.Age > 35
var ageExp = Expression.Property(paramC, typeof(People).GetProperty("Age"));
var ageGreater = Expression.GreaterThan(ageExp, Expression.Constant(35));

// 2. c.Name.Equals("Richard")
var nameExp = Expression.Property(paramC, typeof(People).GetProperty("Name"));
var equalsMethod = typeof(string).GetMethod("Equals", new[] { typeof(string) });
var nameEquals = Expression.Call(nameExp, equalsMethod, Expression.Constant("Richard"));

// 3. c.Id.ToString() == "10"
var idExp = Expression.Field(paramC, typeof(People).GetField("Id"));
var toStringMethod = typeof(int).GetMethod("ToString", Type.EmptyTypes);
var toStringExp = Expression.Call(idExp, toStringMethod);
var idEqual = Expression.Equal(toStringExp, Expression.Constant("10"));

// 4. 用 AndAlso 连接(对应 &&)
var and1 = Expression.AndAlso(idEqual, nameEquals);
var finalExp = Expression.AndAlso(and1, ageGreater);

Expression<Func<People, bool>> lambda =
    Expression.Lambda<Func<People, bool>>(finalExp, paramC);

技巧:遇到复杂表达式,可以先用快捷 Lambda 写出来,再用 ILSpy 等反编译工具查看中间语言,照着拼装。


三、表达式访问者(ExpressionVisitor)

3.1 核心机制

ExpressionVisitor 是遍历和修改表达式目录树的工具,采用访问者模式。

  • Visit(expression):入口方法,判断节点类型后分发到对应的 VisitXxx 方法
  • 表达式树是二叉树结构,Visit 会递归遍历到所有叶节点
  • 重写 VisitXxx 方法可以在任意节点拦截、读取或修改内容
  • 返回新节点即可修改表达式树,返回原节点则保持不变

3.2 修改表达式树(OperationsVisitor)

通过重写 VisitBinary,可以在遍历时把加法替换成减法、乘法替换成除法:

public class OperationsVisitor : ExpressionVisitor
{
    public Expression Modify(Expression expression)
    {
        return Visit(expression);
    }

    protected override Expression VisitBinary(BinaryExpression b)
    {
        if (b.NodeType == ExpressionType.Add)
        {
            Expression left = Visit(b.Left);
            Expression right = Visit(b.Right);
            return Expression.Subtract(left, right); // 加法 → 减法
        }
        if (b.NodeType == ExpressionType.Multiply)
        {
            Expression left = Visit(b.Left);
            Expression right = Visit(b.Right);
            return Expression.Divide(left, right); // 乘法 → 除法
        }
        return base.VisitBinary(b);
    }
}

// 使用
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;
var visitor = new OperationsVisitor();
Expression modified = visitor.Modify(exp);
// 原来 m * n + 2,修改后变成 m / n - 2

3.3 解析表达式为 SQL(ConditionBuilderVisitor)

用栈来收集每个节点转换出的 SQL 片段,最终拼接成完整条件:

public class ConditionBuilderVisitor : ExpressionVisitor
{
    private Stack<string> _StringStack = new Stack<string>();

    public string Condition()
    {
        string condition = string.Concat(_StringStack.ToArray());
        _StringStack.Clear();
        return condition;
    }

    // 二元表达式:a > b、a && b 等
    protected override Expression VisitBinary(BinaryExpression node)
    {
        _StringStack.Push(")");
        Visit(node.Right);
        // ToSqlOperator() 是自定义扩展方法,将 ExpressionType 映射为 SQL 运算符
        // 如 AndAlso/And → "AND",Equal → "=",GreaterThan → ">" 等(见本章末尾映射表)
        _StringStack.Push(" " + node.NodeType.ToSqlOperator() + " ");
        Visit(node.Left);
        _StringStack.Push("(");
        return node;
    }

    // 成员访问:c.Age、c.Name
    // 注意:如果是外部变量(闭包捕获),需要通过反射取值,而不是直接输出字段名
    protected override Expression VisitMember(MemberExpression node)
    {
        if (node.Expression is ConstantExpression)
        {
            // 外部变量:通过反射获取实际值
            var obj = (node.Expression as ConstantExpression).Value;
            var value = (node.Member as FieldInfo).GetValue(obj);
            _StringStack.Push($"'{value}'");
        }
        else
        {
            // 实体属性:输出列名
            _StringStack.Push($" [{node.Member.Name}] ");
        }
        return node;
    }

    // 常量:10、"abc"
    protected override Expression VisitConstant(ConstantExpression node)
    {
        _StringStack.Push($" '{node.Value}' ");
        return node;
    }

    // 方法调用:Contains、StartsWith、EndsWith
    protected override Expression VisitMethodCall(MethodCallExpression m)
    {
        string format = m.Method.Name switch
        {
            "StartsWith" => "({0} LIKE {1}+'%')",
            "Contains"   => "({0} LIKE '%'+{1}+'%')",
            "EndsWith"   => "({0} LIKE '%'+{1})",
            _ => throw new NotSupportedException(m.NodeType + " is not supported!")
        };
        Visit(m.Object);
        Visit(m.Arguments[0]);
        string right = _StringStack.Pop();
        string left = _StringStack.Pop();
        _StringStack.Push(string.Format(format, left, right));
        return m;
    }
}

ExpressionType 到 SQL 运算符的映射(SqlOperator):

ExpressionTypeSQL
AndAlso / AndAND
OrElse / OrOR
Equal=
NotEqual<>
GreaterThan>
GreaterThanOrEqual>=
LessThan<
LessThanOrEqual<=

使用示例:

Expression<Func<People, bool>> lambda = x =>
    x.Age > 5
    && x.Name.StartsWith("A")
    && x.Name.Contains("B")
    && x.Name.EndsWith("C");

var visitor = new ConditionBuilderVisitor();
visitor.Visit(lambda);
Console.WriteLine(visitor.Condition());
// 输出: ((( [Age] > '5') AND ([Name] LIKE 'A'+'%')) AND ([Name] LIKE '%'+'B'+'%')) AND ([Name] LIKE '%'+'C'))

外部变量捕获的处理:

string name = "AAA";
Expression<Func<People, bool>> lambda = x => x.Age > 5 && x.Name == name || x.Id > 5;
// name 是外部变量,编译后会被包装成 ConstantExpression 的字段
// VisitMember 中检测到 node.Expression is ConstantExpression,通过反射取出 "AAA"

3.4 实战扩展:BatchDelete

将表达式树解析为 SQL WHERE 条件,直接用于数据库操作:

public static void BatchDelete<T>(this IQueryable<T> entities, Expression<Func<T, bool>> expr)
{
    var visitor = new ConditionBuilderVisitor();
    visitor.Visit(expr);
    string condition = visitor.Condition();
    string sql = $"DELETE FROM [{typeof(T).Name}] WHERE {condition}";
    // 执行 sql...
}

// 使用
dbSet.BatchDelete<People>(p => p.Age > 30 && p.Name.StartsWith("A"));
// 生成: DELETE FROM [People] WHERE (( [Age] > '30') AND ([Name] LIKE 'A'+'%'))

四、表达式扩展:And / Or / Not

4.1 为什么需要参数替换

两个独立声明的表达式,参数对象不是同一个实例,直接合并会报错。需要用 ExpressionVisitor 统一替换成同一个参数:

Expression<Func<People, bool>> exp1 = x => x.Age > 5;  // 参数是 x
Expression<Func<People, bool>> exp2 = y => y.Id > 5;   // 参数是 y,不同实例

// 直接 Expression.AndAlso(exp1.Body, exp2.Body) 会出错
// 需要把两个 Body 中的参数都替换成同一个新参数 c

4.2 参数替换访问者(NewExpressionVisitor)

internal class NewExpressionVisitor : ExpressionVisitor
{
    private readonly ParameterExpression _newParameter;

    public NewExpressionVisitor(ParameterExpression param)
    {
        _newParameter = param;
    }

    public Expression Replace(Expression exp) => Visit(exp);

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return _newParameter; // 把所有参数节点替换成新参数
    }
}

4.3 And / Or / Not 扩展方法

public static class ExpressionExtend
{
    public static Expression<Func<T, bool>> And<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        if (expr1 == null) return expr2;
        if (expr2 == null) return expr1;

        ParameterExpression param = Expression.Parameter(typeof(T), "c");
        var visitor = new NewExpressionVisitor(param);
        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, param);
    }

    public static Expression<Func<T, bool>> Or<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        ParameterExpression param = Expression.Parameter(typeof(T), "c");
        var visitor = new NewExpressionVisitor(param);
        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, param);
    }

    public static Expression<Func<T, bool>> Not<T>(
        this Expression<Func<T, bool>> expr)
    {
        var body = Expression.Not(expr.Body);
        return Expression.Lambda<Func<T, bool>>(body, expr.Parameters[0]);
    }
}

注意:Expression.And 对应位运算 &(非短路),Expression.AndAlso 对应 &&(短路)。源码中 And 扩展方法用的是 Expression.And,Or 用的是 Expression.Or。

使用示例:

Expression<Func<People, bool>> exp1 = x => x.Age > 5;
Expression<Func<People, bool>> exp2 = x => x.Id > 5;

var andExp = exp1.And(exp2);  // c => c.Age > 5 & c.Id > 5
var orExp  = exp1.Or(exp2);   // c => c.Age > 5 | c.Id > 5
var notExp = exp1.Not();      // x => !(x.Age > 5)

// 动态构建查询条件
Expression<Func<People, bool>> query = null;
string name = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(name))
    query = query.And(p => p.Name.Contains(name));

string ageStr = Console.ReadLine();
if (int.TryParse(ageStr, out int age))
    query = query.And(p => p.Age > age);

var result = dbSet.Where(query).ToList();

五、对象映射(高性能 Mapper)

5.1 五种方案对比

方案性能灵活性说明
硬编码⭐⭐⭐⭐⭐⭐手写赋值,不通用
反射(ReflectionMapper)⭐⭐⭐⭐⭐⭐每次都要反射,慢
序列化(SerializeMapper)⭐⭐⭐⭐⭐JSON 序列化再反序列化,慢
表达式树+字典缓存(ExpressionMapper)⭐⭐⭐⭐⭐⭐⭐⭐⭐首次拼装,后续走字典取委托
表达式树+泛型缓存(ExpressionGenericMapper)⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐最优,泛型副本天然隔离

5.2 反射方案(最慢)

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

5.3 序列化方案(慢)

public static TOut Trans<TIn, TOut>(TIn tIn)
{
    string json = JsonConvert.SerializeObject(tIn);
    return JsonConvert.DeserializeObject<TOut>(json);
}

5.4 表达式树+字典缓存(ExpressionMapper)

用 Dictionary<string, object> 缓存编译好的委托,key 是类型组合字符串。首次调用拼装并编译,后续直接从字典取委托执行:

private static Dictionary<string, object> _Dic = new Dictionary<string, object>();

public static TOut Trans<TIn, TOut>(TIn tIn)
{
    string key = $"funckey_{typeof(TIn).FullName}_{typeof(TOut).FullName}";
    if (!_Dic.ContainsKey(key))
    {
        // 拼装表达式:p => new TOut { Prop1 = p.Prop1, ... }
        ParameterExpression param = Expression.Parameter(typeof(TIn), "p");
        List<MemberBinding> bindings = new List<MemberBinding>();

        foreach (var prop in typeof(TOut).GetProperties())
        {
            var sourceProp = Expression.Property(param, typeof(TIn).GetProperty(prop.Name));
            bindings.Add(Expression.Bind(prop, sourceProp));
        }
        foreach (var field in typeof(TOut).GetFields())
        {
            var sourceField = Expression.Field(param, typeof(TIn).GetField(field.Name));
            bindings.Add(Expression.Bind(field, sourceField));
        }

        var memberInit = Expression.MemberInit(Expression.New(typeof(TOut)), bindings.ToArray());
        var lambda = Expression.Lambda<Func<TIn, TOut>>(memberInit, param);
        _Dic[key] = lambda.Compile();
    }
    return ((Func<TIn, TOut>)_Dic[key]).Invoke(tIn);
}

注意:_Dic 的 ContainsKey + 写入不是原子操作,多线程并发时存在竞态条件。生产环境建议改用 ConcurrentDictionary 或加锁,或直接使用泛型缓存方案。

5.5 表达式树+泛型缓存(ExpressionGenericMapper,最优)

泛型类的静态字段天然为每组类型生成独立副本,无需字典查找,性能更高:

public class ExpressionGenericMapper<TIn, TOut>
{
    private static readonly Func<TIn, TOut> _FUNC;

    static ExpressionGenericMapper()
    {
        ParameterExpression param = Expression.Parameter(typeof(TIn), "p");
        List<MemberBinding> bindings = new List<MemberBinding>();

        // 处理属性
        foreach (var prop in typeof(TOut).GetProperties())
        {
            var sourceProp = Expression.Property(param, typeof(TIn).GetProperty(prop.Name));
            bindings.Add(Expression.Bind(prop, sourceProp));
        }
        // 处理字段
        foreach (var field in typeof(TOut).GetFields())
        {
            var sourceField = Expression.Field(param, typeof(TIn).GetField(field.Name));
            bindings.Add(Expression.Bind(field, sourceField));
        }

        var memberInit = Expression.MemberInit(Expression.New(typeof(TOut)), bindings.ToArray());
        var lambda = Expression.Lambda<Func<TIn, TOut>>(memberInit, param);
        _FUNC = lambda.Compile(); // 只执行一次
    }

    public static TOut Trans(TIn t) => _FUNC(t);
}

// 使用
PeopleCopy copy = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);

泛型缓存的原理: ExpressionGenericMapper<People, PeopleCopy> 和 ExpressionGenericMapper<User, UserDto> 是两个不同的类,各自有独立的静态字段 _FUNC,CLR 保证每组类型只初始化一次。


六、核心知识点总结

6.1 为什么要用表达式目录树?

  • 动态性:在运行时动态构建查询逻辑,把程序写活
  • 可分析性:可以解析表达式结构,转换为 SQL、MongoDB 查询、ES DSL 等
  • 类型安全:编译时检查,避免字符串拼接 SQL 的错误和注入风险
  • 高性能:配合缓存,性能接近硬编码

6.2 常用表达式节点速查

类型说明创建示例
ConstantExpression常量Expression.Constant(10)
ParameterExpression参数Expression.Parameter(typeof(int), "x")
BinaryExpression二元运算(加减乘除、比较、逻辑)Expression.Add(a, b) / Expression.GreaterThan(a, b)
MemberExpression成员访问(属性/字段)Expression.Property(obj, "Name") / Expression.Field(obj, fi)
MethodCallExpression方法调用Expression.Call(obj, method, args)
MemberInitExpression对象初始化Expression.MemberInit(newExp, bindings)
LambdaExpressionLambda 整体Expression.Lambda<Func<...>>(body, params)

6.3 实际应用场景

  • ORM 框架:Entity Framework、Dapper 等将 LINQ 表达式树解析为 SQL
  • 动态查询:根据用户输入拼装 WHERE 条件,替代字符串拼接 SQL
  • 对象映射:AutoMapper 底层原理,动态生成硬编码级别的映射委托
  • 规则引擎:运行时动态构建业务规则
  • 批量操作扩展:如 BatchDelete<T> 直接从表达式生成 DELETE SQL
  • 代码生成:运行时动态生成高性能执行逻辑

6.4 学习建议

  • 理解本质:表达式树是数据结构,不是可执行代码
  • 从简单开始:先掌握基础拼装,再学习复杂场景
  • 善用反编译:用 ILSpy 等工具查看快捷 Lambda 编译后的中间语言,照着拼装
  • 性能意识:合理使用缓存,避免重复拼装;优先选泛型缓存而非字典缓存

记住:表达式目录树 = 动态 + 类型安全 + 高性能

C#表达式目录树vs实用插件 C#在学习表达式目录树的时候,好的工具会让你的学习事半功倍,能够更好的帮助你学习和理解,希望能够帮助到你。 立即下载

相关推荐

C#简单实现表达式目录树(Expression)

表达式目录树以数据形式表示语言级别代码。数据存储在树形结构中。表达式目录树中的每个节点都表示一个表达式。这篇文章给大家介绍C#简单实现表达式目录树(Expression),需要的朋友参考下吧

C#表达式目录树系列之1 -- 表达式目录树基本概念

概要 本文主要是帮助读者搞清楚什么是表达书目录树,表达书目录树能做什么,如何创建表达书目录树。后续几篇文章侧重于表达书目录树的具体应用。 表达式目录树是什么 表达式目录树是一种树型结构,它将代码以数据的形式来存储在树的各个节点中,树型结构的每个节点都是一个表达式。 这句话初听很拗口,举个例子。相信大家都使用过ADO.NET中的SqlCommand类,把拼装好的SQL代码作为参数实例化该类,SQL代码就能执行。 事实上,这种方式采用了和表达式目录树同样的设计思想。只不过SQL代码是以字符串的形式存储。这种设计

weixin_43263355的博客 2694

运算放大器电路仿真实践:从零实现完整示例

通过一个完整的运算放大器电路仿真示例,深入掌握电路仿真的关键步骤与技巧,帮助电子爱好者和工程师快速上手实际项目设计。

weixin_34725745的博客 1317

09-01 C#表达式目录树

目录一、定义二、与委托的区别1、在扩展方法表达式中的区别2、声明方式的区别3、执行的区别三、表达式目录树的本质 一、定义 表达式目录树是一种语法树,是一种数据结构 二、与委托的区别 1、在扩展方法表达式中的区别 List<Person> persons = new Person().Query(); persons.Where(p => p.Id == 1); // where扩展方法传入的是一个委托 persons.AsQueryable().Where(p => p.Id

菜鸟爱飞不飞的博客 1360

【backtrader保姆级教学】投资组合回测

method1:探索投资组合的最有方案,使用蒙特卡洛模拟Markowitz模型。# 提取最小波动组合对应的权重, 并转换成Numpy数组。# 绘制收益-标准差的散点图,并用颜色描绘夏普比率。# 在收益-风险散点图中突出风险最小的点。:param any_day: 任意日期。# 将该点坐标显示在图中并保留四位小数。password = “替换密码”# 找到标准差最小数据的索引值。user = “替换账号”# 计算GMV投资组合收益。# 计算每项资产的夏普比率。# 设置无风险回报率为0。

weixin_38132951的博客 2314

音频功放电路大全

作为硬件工程师,特别是做纯粹模拟电路、应用于音频功放的工程师,对于A类,B类,AB类,D类,G类,H类,T类功放应该特别熟悉。大多数工程师或许只知道其中的一部分、或者知道大概,为了让更多的工程师掌握更加详尽的音频功放知识,下文对以上说的音频功放做详细的说明。 功放,顾名思义,就是功率放大的缩写。与电压或者电流放大来说,功放要求获得一定的、不失真的功率,一般在大信号状态下工作,因此,功放电路一般包含电压放大或者电流放大电路没有的特殊问题,具体表现在:①输出功率尽可能大;②通常在大信号状态下工作;③非线性失真突

ltqdxl的博客 6593

C# .Net学习笔记—— Expression 表达式目录树

C#学习,表达式目录树

weixin_46711336的博客 2323

基于STM32与MPU6050的实时姿态检测系统设计与实现(源码+硬件解析)

本文详细介绍了基于STM32单片机与MPU6050传感器的实时姿态检测系统设计与实现。通过硬件解析、传感器校准、卡尔曼滤波算法和欧拉角计算,实现高精度姿态检测。提供完整源码和调试技巧,适用于无人机、平衡车等嵌入式开发项目,解决噪声干扰和数据漂移等常见问题。

jupi8的博客 493

C#表达式目录树一

文章目录什么是表达式目录树Expression表达式目录树的本质表达式目录树的拼装拼装示例一拼装示例二拼装示例三 什么是表达式目录树Expression 表达式目录树的本质 以前我们写Linq查询条件像这样: new List<int>().Where(i => i > 10); 我们AsQueryable()一下: new List<int>().AsQueryable().Where(i => i > 10); 我们查看AsQueryable的w

wukai1211的博客 1225

【低空经济】森林火情高精度监测与早期预警无人机巡护方案

在全球范围内,森林火灾已成为一个严重的生态和社会问题。它不仅对自然生态系统造成了毁灭性的影响,还对人类的生命财产安全构成了极大的威胁。根据国际森林发展组织的统计,全球每年因森林火灾造成的经济损失高达数百亿美元,甚至在某些年份,火灾损失占到某些国家国民经济总量的相当一部分。因此,开展高效的森林火情监测与早期预警工作显得尤为重要。随着科技的发展,无人机作为新兴的监测工具,以其高效、灵活和经济的特点在森林火灾监测领域展现出了巨大的潜力。

2502_92579126的博客 1211

Vivado图形化界面烧写MCS文件到SPI FLASH全流程(附常见报错解决方案)

本文详细介绍了使用Vivado图形化界面将MCS文件烧录至SPI FLASH的完整操作流程。内容涵盖从环境准备、MCS文件生成到硬件连接与烧写的每一步,并针对SPI总线宽度报错、FLASH型号识别失败等常见问题提供了深度解决方案,帮助用户高效完成FPGA配置,摆脱对TCL命令行的依赖。

s8t9u0v1w的博客 534

C# 中的 表达式树

这节来讲一下C#中的表达式树(又称表达式目录树、Expression)。什么是表达式树?表达式树是一种C#中的数据结构,它以树的形式表示某些代码内部的结构。每个节点是一种称为表达式的C#对象,例如二元运算,方法调用,常量等。这种数据结构主要用于LINQ查询的内部机制和动态编程。在C#中,表达式树使在编译时表达式的结构和操作被保留下来,而不是像通常的.net代码那样被直接编译成IL。...

dotNET跨平台 441

逆变器方案(工频全套)工频正弦波逆变器开发板全套设计资

逆变器方案(工频全套)工频正弦波逆变器开发板,24V-72V通用12只TO-247封装MOS管,额定输出功率6500W以下;配有触摸屏操作界面,运行数据一目了然,带市电互补UPS功能,可选择电池优先或市电有限工作,我们的开发板均从实战角度出发,让您的学习更便捷,包含全套设计资料,PCB.原理图.源代码,程序均有中文注释,MCU选用美国微芯公的PIC-8位单片机,民用数字电源首选单片机,抗干扰能力强,运行稳定。...

m0_73494033的博客 890

06-C#

动态性:在运行时动态构建查询逻辑,把程序写活可分析性:可以解析表达式结构,转换为 SQL、MongoDB 查询、ES DSL 等类型安全:编译时检查,避免字符串拼接 SQL 的错误和注入风险高性能:配合缓存,性能接近硬编码。

噢~ 308

硬件级Dalvik字节码粒度无痕HOOK及VMP取址码定位分析

2.通过硬件读写断点的输出信息 可知pc寄存器就是art解释器的取码地址 直接硬件执行断点在这个pc 即可直接trace所有的smali执行流 通杀所有机型系统。本文即将探讨的是 如何在硬件级别实现dalvik bytecode粒度的无痕拦截技术 并实现鼠标点击一键hook 指哪儿打哪儿 感受 button power 的强大魅力!4.由于硬件断点是同步的 断下后可随时硬件dump下这一瞬间的app内存映像 写入unicorn的内存模拟执行。解释器在解释执行前必会读取内存中的bytecode。

2503_90751789的博客 1084

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

我整理的.Net FrameWork发展史

.Net FrameWork发展史 1.0 1.0是NET最早的一个版本,是第一个微软Visual Studio .NET的发行版的一部分。可以以一个独立且可重新分发的包的形式或在一个软件发展工具包集中被获得,不能安装在用户操作系统和服务器操作系统上。主要包括公共语言运行库CLR1.0、BCL类库和ASP.NET开发框架 CLR:1.0 C#:1.0 IDE:Visu

8154

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

从接口说起——自定义LINQ Provider实现LINQ to LDAP查询(其一)

引言 一段很长很无聊的故事 2011下半年的时候开始接触.NET同时就接触了LINQ to SQL。好吧当时我认为LINQ to SQL就是一切(大三的C#课程老师也如此认为)。好在博客园的几个大牛都对这个概念进行了阐述,这里可以借花献佛。 其一,http://www.cnblogs.com/Terrylee/archive/2009/01/05/LINQ-and-LINQ-to-SQL.h...

weixin_33962621的博客 177

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

C# 表达式目录树生成工具

表达式目录树生成封装

yexuanbaby的专栏 306

Expression Trees--C#

https://docs.microsoft.com/en-us/dotnet/csharp/expression-trees 一,表达式树能做什么   1)表达式树加强方法和参数的交互;   2)表达式树可以在运行时操作代码,比如检查运行的算法,增加新的功能。 二,表达式树是什么   以var sum = 1 + 2为例,该语句就可以看作表达式树: 声明变量(var sum) v...

mucangmang的博客 1146

C# 表达式目录树知识点

C# 中的表达式目录树(Expression Trees)是用来表示编译器可识别的代码构造的树状数据结构。它们可以在运行时构造、修改和执行代码。1.反射发出:表达式目录树可以用来代替反射发出(Reflection Emit),创建动态方法和类。4.表达式导航:在编译时不能确定的条件下,可以在运行时构建表达式目录树来表示程序流程。3.动态查询:表达式目录树可以用于构建动态查询表达式,如 LINQ。一、表达式目录树,在字典中的应用。二、表达式目录树,在泛型中的应用。

linxiaozi2020的博客 204

C# Expression表达式目录树

Expression就是表达式目录树,是以树形数据结构表示代码,其中每一个节点都是一种表达式。 用lambda表达式来创建一个简单的Expression 使用lambda表达式,编译器在生成IL时会帮我们拼装表达式目录树,示例: Expression<Func<int, int, int>> expr = (a, b) => a * b + 3; 调试查看表达式的结...

539

C#中的表达式目录树

表达式目录树Expression 位于Linq命名空间中,功能强大,但是相对也比较难于学习,下面实例是一个表达式目录树的一个简单的应用:模型转换。说明:通过泛型缓存提高性能,也可以通过字典进行缓存,但是相对的效率会低。 首先准备两个实体类 public class Person { public string Name { get; set; } pub...

weixin_33918114的博客 873

C#表达式目录树系列之2 --常见的表达式目录树的实例

概要 本文主要列举出一些常用的表达式目录树实例,便于以此为基础,构建更复杂的表达式目录树,以满足各种多变的业务场景。 表达式目录树的构建,除了使用Expression类提供的静态方法外,一般还需要同反射结合在一起。例如通过反射找到类中具体定义的方法,通过反射找到类中的构造函数等。 常用表达式目录树构建实例 Student类的定义详见附录。 访问对象的属性 构建目标 s => s.FirstName s是Student类型 代码如下: ParameterExpression sParameter = E

weixin_43263355的博客 2255

C# 表达式目录树Expression

表达式目录树 表达式目录树:语法树,或者说是一种数据结构 1.表达式目录树Expression:System.Linq.Expressions; 2.描述了多个变量或者和常量之间的关系,按照一定的规则进行组装! 可以向委托一样使用lambd表达式快捷声明; 不能有语句体,声明只能有一行代码; 可以通过Compile(),编译成一个委托; Func<int, int, int> func = (m, n) => { int i = 0; return m * n + 2;

qq_29821795的博客 1010

表达式目录树(一)

(一)Lambda创建表达式目录树Expression<Func<int, int, int>> exp1 = (a, b) => a * b+2;说明一下:FuncFunc<(Of <(T1, T2, TResult>)>)泛型委托:封装一个具有两个参数并返回 TResult 参数指定的类型值的方法。T1:此委托封装的方法的第一个参数类型。T2:此委托封装的方法的第二个参数类型。Tresult:此

极客神殿 2635

Expression Tree上手指南 (一)

大家可能都知道Expression Tree是.NET 3.5引入的新增功能。不少朋友们已经听说过这一特性,但还没来得及了解。看看博客园里的老赵等诸多牛人,将Expression Tree玩得眼花缭乱,是否常常觉得有点落伍了呢?其实Expression Tree是一个一点就透的特性,只要对其基本概念有了一定的了解,就可以自己发挥出无数的用法。特别是之前对Reflection,泛型等知识有过一些了解...

weixin_33883178的博客 265
上一篇: 05-C#.Net-Lambda与LINQ-学习笔记
下一篇: 07-C#.Net-数据结构-学习笔记
似水明俊德
博客等级 码龄8年 247粉丝 276原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值