在运行时创建一个可以计算的表达式。
在运行时创建一个可以计算的表达式。
我有一个产品列表,需要创建可以持久化、检索和执行的表达式树。这是为客户端计算构建器而设计的。
我对表达式还不太熟悉,虽然我已经阅读了相当多的文档,但学习曲线有点陡峭。我想要的是能够先积累PropertyExpression和Operand对。以下是我目前的进展,不确定是否正确地构建了它。
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace ConsoleApplication1 { public enum ProductType { Perishable, Fixed, Miscellaneous } public enum OperandType { Addition, Subtraction, Multiplication, Division } public class Product { public string Name { get; set; } public ProductType Type { get; set; } public float Price { get; set; } } public class Configuration { public DictionaryDictionary { get; set; } } public class Operand { public OperandType Type { get; set; } } public class CalculationPair where TEntityType : class where TProperty : struct { public ValueTypeProperty Left { get; set; } public Operand Operand { get; set; } public ValueTypeProperty Right { get; set; } // How to specify TResult as an [out] parameter? public TResult Calculate () where TResult : struct { TResult result = default(TResult); if (this.Operand.Type == OperandType.Multiplication) { // How to execute the expression? //result = this.Left * this.Right; } return result; } } public class ValueTypeProperty where TEntityType : class where TProperty : struct { public string Name { get; set; } public Expression > PropertyExpression { get; set; } } public class ProductPriceProperty : ValueTypeProperty { } public static class Program { public static void Main() { Configuration config = new Configuration(); List products = new List (); config.Dictionary.Add("ExportFactor", 80); config.Dictionary.Add("ChannelMargin", 100); products.Add(new Product() { Name = "1", Type = ProductType.Fixed, Price = 10 }); products.Add(new Product() { Name = "2", Type = ProductType.Miscellaneous, Price = 20 }); products.Add(new Product() { Name = "3", Type = ProductType.Perishable, Price = 30 }); foreach (var product in products) { if (product.Type == ProductType.Fixed) { CalculationPair calculation = new CalculationPair () { Left = new ProductPriceProperty() { Name = "Product Price", PropertyExpression = (entity => entity.Price) }, Operand = new Operand() { Type = OperandType.Multiplication }, Right = new ProductPriceProperty() { Name = "ExportFactor", PropertyExpression = (entity => config.Dictionary["ExportFactor"]) }, }; // Calculation needs to be persisted to be retrieved later. // ???! // Once calculation has been reconstructed from the persistence layer, it needs to be executed. product.Price = calculation.Calculate (); } } } } }
更新:以下是我在优先顺序上遇到的问题:
- 如何在`CalculationPair.Calculate
- 如何在`CalculationPair.Calculate
- 如何持久化计算表达式并在以后检索它?
创建一个可以在运行时计算的表达式的原因是,需要根据不同的条件进行动态计算。这可以通过使用闭包匿名方法或表达式树来实现。
在给出的示例中,使用了闭包匿名方法来创建可以在运行时计算的表达式。代码中定义了一个名为CalculationPair
在Main方法中的示例代码中,首先创建了一个CalculationPair
在CalculationPair类中,定义了一个Calculate方法,该方法接受一个实体对象作为参数,并根据Left、Operand和Right属性的值进行计算。首先创建了一个ParameterExpression对象,然后使用ParameterRewriter类对Left和Right属性的表达式进行重写,将其中的entity参数替换为实际的实体对象。接下来根据Operand的类型,使用Expression类创建相应的表达式树。最后,使用Expression.Lambda方法将表达式树编译为一个委托,并调用该委托进行计算。
在使用时,可以通过调用Calculate方法来计算结果,并将结果赋值给相应的属性。
需要注意的是,这段代码是混合使用了闭包匿名方法和表达式树的方式。闭包匿名方法用于创建动态计算的表达式,而表达式树用于解析和重写表达式。闭包是指一个匿名方法使用了来自参数、内部作用域等的变量,从而与这些变量相关联。
关于表达式树和闭包的更多信息,可以参考以下链接:
- 表达式树:stackoverflow.com/questions/10005948
- 闭包:stackoverflow.com/questions/595482
通过理解这些概念,可以更好地理解不同的实现方式,并根据需求选择合适的方法来创建动态计算的表达式。