【发布时间】:2013-12-29 19:45:49
【问题描述】:
我有一个产品列表,我需要根据这些产品创建表达式树,这些表达式树可以被持久化,以后可以检索和执行。这适用于客户端计算生成器。
我是 Expressions 的新手,虽然我已经阅读了相当多的文档,但这里的学习曲线有点陡峭。我想要的是能够积累 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, Sunbtraction, 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<string, float> Dictionary { get; set; }
}
public class Operand
{
public OperandType Type { get; set; }
}
public class CalculationPair<TEntityType, TProperty>
where TEntityType: class
where TProperty: struct
{
public ValueTypeProperty<TEntityType, TProperty> Left { get; set; }
public Operand Operand { get; set; }
public ValueTypeProperty<TEntityType, TProperty> Right { get; set; }
// How to specify TResult as an [out] parameter?
public TResult Calculate<TResult> ()
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<TEntityType, TProperty>
where TEntityType: class
where TProperty: struct
{
public string Name { get; set; }
public Expression<Func<TEntityType, TProperty>> PropertyExpression { get; set; }
}
public class ProductPriceProperty:
ValueTypeProperty<Product, float>
{
}
public static class Program
{
public static void Main ()
{
Configuration config = new Configuration();
List<Product> products = new List<Product>();
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<Product, float> calculation = new CalculationPair<Product, float>()
{
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 reconstruction from the persistence layer, it needs to be executed.
product.Price = calculation.Calculate<float>();
}
}
}
}
}
更新:以下是我正在努力解决的优先级顺序:
-
CalculationPair.Calculate<TReult>()函数中的表达式如何执行? - 如何在
CalculationPair.Calculate<TReult>()函数中将TResult指定为[out]参数? - 如何将计算表达式持久化并稍后检索?
【问题讨论】:
-
为什么不使用内置的表达式树而不是从头开始重写所有内容?您只需要提供序列化逻辑,其他一切(包括稍后执行表达式)都是完全免费的。
-
@Jon:尽管我已尝试阅读它,但我不清楚我正在尝试的内容与您的建议之间的区别。这将用于表达式/计算构建器,因此具有更多控制权是可取的。如果我没记错的话,网络上的大多数表达式构建器示例都使用内置树并将它们用于过滤目的,而不是基于用户指定的公式进行值操作。
-
您正试图从头开始编写内置表达式树的设计欠佳且(编译器)支持极差的子集。我建议使用内置插件(适当的子集)——只要你需要,你的代码不会正确处理所有理论案例,它也不需要。的确,大多数示例都面向过滤,但在任何地方都没有硬性限制。您可以使用 expr 树来表达任何不需要变异状态的东西,以及许多需要改变状态的东西。
-
@Jon:谢谢你的解释,我同意。请您指出其中一个示例作为起点。考虑到我基于这个问题的经验。我想我一开始很难掌握如何开始。
标签: c# .net linq reflection expression