MST
星途 面试题库

面试题:C# 表达式树与运算符优化

在 C# 中,如何利用表达式树来动态构建和优化包含复杂运算符的表达式?例如,对于一个由用户输入的字符串表示的数学表达式(如 "3 * x + 2 * y",其中 `x` 和 `y` 为变量),如何将其转换为表达式树,并进行必要的优化(如常量折叠)后执行,给出实现思路和关键代码片段。
43.9万 热度难度
编程语言C#

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 解析字符串表达式:使用词法分析和语法分析技术将输入的字符串(如 "3 * x + 2 * y")分解为一个个的标记(token),例如数字、变量名、运算符等,并构建语法树。
  2. 构建表达式树:根据解析得到的语法树,使用C#的表达式树相关类(如 Expression 类及其派生类)来构建对应的表达式树。
  3. 优化表达式树:通过常量折叠等优化技术,在表达式树中直接计算可以在编译期确定的常量表达式,减少运行时计算量。例如对于 "3 * 2" 这样的子表达式,在表达式树构建过程中直接计算结果为 6 并替换原表达式。
  4. 编译和执行表达式树:将优化后的表达式树编译为可执行的委托,通过传递变量的值来执行该委托并得到最终结果。

关键代码片段

using System;
using System.Linq.Expressions;
using System.Collections.Generic;

public class ExpressionEvaluator
{
    private Dictionary<string, double> variables = new Dictionary<string, double>();

    public void SetVariable(string name, double value)
    {
        variables[name] = value;
    }

    public double Evaluate(string expression)
    {
        // 简单的词法分析,这里仅作示意,实际需更完善
        string[] tokens = expression.Split(' ');
        Stack<Expression> stack = new Stack<Expression>();
        foreach (string token in tokens)
        {
            if (double.TryParse(token, out double number))
            {
                stack.Push(Expression.Constant(number));
            }
            else if (variables.ContainsKey(token))
            {
                stack.Push(Expression.Constant(variables[token]));
            }
            else if (token == "+" || token == "-" || token == "*" || token == "/")
            {
                Expression right = stack.Pop();
                Expression left = stack.Pop();
                switch (token)
                {
                    case "+":
                        stack.Push(Expression.Add(left, right));
                        break;
                    case "-":
                        stack.Push(Expression.Subtract(left, right));
                        break;
                    case "*":
                        stack.Push(Expression.Multiply(left, right));
                        break;
                    case "/":
                        stack.Push(Expression.Divide(left, right));
                        break;
                }
            }
        }
        Expression finalExpression = stack.Pop();
        // 常量折叠优化,实际可更完善
        LambdaExpression lambda = Expression.Lambda(finalExpression);
        Delegate compiled = lambda.Compile();
        return (double)compiled.DynamicInvoke();
    }
}

使用示例:

class Program
{
    static void Main()
    {
        ExpressionEvaluator evaluator = new ExpressionEvaluator();
        evaluator.SetVariable("x", 5);
        evaluator.SetVariable("y", 10);
        double result = evaluator.Evaluate("3 * x + 2 * y");
        Console.WriteLine(result);
    }
}