如果你将表达式构建为二叉树,其中叶子节点是值,非叶子节点是对这些值进行操作的运算符,那么你可以做到这一点。构建它们很笨拙,但你有很多的能力。
using System;
public class Program
{
public static void Main()
{
var result = new AssignmentNode("x", new AddNode(new ValueNode("y", 10), new ValueNode("z", 20)));
Console.WriteLine(result.GetStringValue());
}
}
public abstract class ArithmeticNode
{
public abstract double GetNumericValue();
public abstract string GetStringValue();
}
public abstract class OperatorNode : ArithmeticNode
{
public ArithmeticNode Left { get; }
public ArithmeticNode Right { get; }
public string Symbol { get; }
protected OperatorNode(ArithmeticNode left, ArithmeticNode right, string symbol)
{
Left = left;
Right = right;
Symbol = symbol;
}
protected abstract double Operate(double left, double right);
public override double GetNumericValue()
{
return Operate(Left.GetNumericValue(), Right.GetNumericValue());
}
public override string GetStringValue()
{
return string.Format("({0} {1} {2})", Left.GetStringValue(), Symbol, Right.GetStringValue());
}
}
public class AddNode : OperatorNode
{
public AddNode(ArithmeticNode left, ArithmeticNode right)
: base(left, right, "+") { }
protected override double Operate(double left, double right)
{
return left + right;
}
}
public class ValueNode : ArithmeticNode
{
public string Name { get; }
public double Value { get; }
public ValueNode(string name, double value)
{
Name = name;
Value = value;
}
public override double GetNumericValue()
{
return Value;
}
public override string GetStringValue()
{
return string.Format("{0}({1})", Name, Value);
}
}
public class AssignmentNode : ArithmeticNode
{
public string Name { get; }
public ArithmeticNode Body { get; }
public AssignmentNode(string name, ArithmeticNode body)
{
Name = name;
Body = body;
}
public override double GetNumericValue()
{
return Body.GetNumericValue();
}
public override string GetStringValue()
{
return string.Format("{0} = {1} = {2})", Name, Body.GetStringValue(), Body.GetNumericValue());
}
}
输出:
x = (y(10) + z(20)) = 30)
消除括号,但仅在必要的情况下,本身就是一项挑战。
执行速度也不会是世界上最快的 - 您已将快速数值相加交换为缓慢的虚方法调用。您可以通过使用编译表达式来改进:
using System;
using System.Linq.Expressions;
public class Program
{
public static void Main()
{
var result = new AssignmentNode("x", new AddNode(new ValueNode("y", 10), new ValueNode("z", 20)));
Console.WriteLine(result.GetStringValue());
}
}
public abstract class ArithmeticNode
{
private Func<double> computer;
public abstract string GetStringValue();
public abstract Expression GetExpression();
public double GetNumericValue()
{
if (computer == null)
{
computer = Expression.Lambda<Func<double>>(GetExpression()).Compile();
}
return computer();
}
}
public abstract class OperatorNode : ArithmeticNode
{
public ArithmeticNode Left { get; }
public ArithmeticNode Right { get; }
public string Symbol { get; }
protected OperatorNode(ArithmeticNode left, ArithmeticNode right, string symbol)
{
Left = left;
Right = right;
Symbol = symbol;
}
protected abstract Expression Operate(Expression left, Expression right);
public override Expression GetExpression()
{
return Operate(Left.GetExpression(), Right.GetExpression());
}
public override string GetStringValue()
{
return string.Format("({0} {1} {2})", Left.GetStringValue(), Symbol, Right.GetStringValue());
}
}
public class AddNode : OperatorNode
{
public AddNode(ArithmeticNode left, ArithmeticNode right)
: base(left, right, "+") { }
protected override Expression Operate(Expression left, Expression right)
{
return Expression.Add(left, right);
}
}
public class ValueNode : ArithmeticNode
{
public string Name { get; }
public double Value { get; }
public ValueNode(string name, double value)
{
Name = name;
Value = value;
}
public override Expression GetExpression()
{
return Expression.Constant(Value);
}
public override string GetStringValue()
{
return string.Format("{0}({1})", Name, Value);
}
}
public class AssignmentNode : ArithmeticNode
{
public string Name { get; }
public ArithmeticNode Body { get; }
public AssignmentNode(string name, ArithmeticNode body)
{
Name = name;
Body = body;
}
public override Expression GetExpression()
{
return Body.GetExpression();
}
public override string GetStringValue()
{
return string.Format("{0} = {1} = {2})", Name, Body.GetStringValue(), Body.GetNumericValue());
}
}
可能有一种解析Linq表达式以产生相同结果的方法,但这超出了我的能力范围。
+
),每个叶子节点都是数字。然后可以评估您的树(+
节点通过添加其两个子节点的值返回一个值,等等),或将其转换为字符串(+
节点通过获取其两个子节点的字符串值并在它们之间添加 "+" 符号来构造一个值)。当您想要避免不必要的括号时(例如显示 "a + b + c" 而不是 "(a + b) + c")时,生活变得有趣。 - canton7