在运行时创建一个可以计算的表达式。

18 浏览
0 Comments

在运行时创建一个可以计算的表达式。

我有一个产品列表,需要创建可以持久化、检索和执行的表达式树。这是为客户端计算构建器而设计的。

我对表达式还不太熟悉,虽然我已经阅读了相当多的文档,但学习曲线有点陡峭。我想要的是能够先积累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 Dictionary Dictionary { 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()`函数中将TResult指定为[out]参数?

- 如何持久化计算表达式并在以后检索它?

0
0 Comments

创建一个可以在运行时计算的表达式的原因是,需要根据不同的条件进行动态计算。这可以通过使用闭包匿名方法或表达式树来实现。

在给出的示例中,使用了闭包匿名方法来创建可以在运行时计算的表达式。代码中定义了一个名为CalculationPair的泛型类,该类包含了Left、Operand、Right和Calculator等属性。通过设置这些属性,可以构建一个可以在运行时计算的表达式。

在Main方法中的示例代码中,首先创建了一个CalculationPair的实例,然后设置了Left、Operand、Right和Calculator等属性。其中,Calculator属性使用了闭包匿名方法,根据实体的属性和配置对象的属性进行计算。

在CalculationPair类中,定义了一个Calculate方法,该方法接受一个实体对象作为参数,并根据Left、Operand和Right属性的值进行计算。首先创建了一个ParameterExpression对象,然后使用ParameterRewriter类对Left和Right属性的表达式进行重写,将其中的entity参数替换为实际的实体对象。接下来根据Operand的类型,使用Expression类创建相应的表达式树。最后,使用Expression.Lambda方法将表达式树编译为一个委托,并调用该委托进行计算。

在使用时,可以通过调用Calculate方法来计算结果,并将结果赋值给相应的属性。

需要注意的是,这段代码是混合使用了闭包匿名方法和表达式树的方式。闭包匿名方法用于创建动态计算的表达式,而表达式树用于解析和重写表达式。闭包是指一个匿名方法使用了来自参数、内部作用域等的变量,从而与这些变量相关联。

关于表达式树和闭包的更多信息,可以参考以下链接:

- 表达式树:stackoverflow.com/questions/10005948

- 闭包:stackoverflow.com/questions/595482

通过理解这些概念,可以更好地理解不同的实现方式,并根据需求选择合适的方法来创建动态计算的表达式。

0