I have a list of products against which I need to create expression trees that can be persisted and later retrieved and executed. This is for a client-side calculation builder.
I am new to Expressions and although I have read a reasonable amount of documentation, the learning curve is a little steep here. What I want is to be able to accumulate PropertyExpression and Operand pairs to start with. Here is what I have so far and am not sure if I have structured it correctly.
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>();
}
}
}
}
}
UPDATE: Here is what I am struggling with in order of priority:
- How to execute the expression in the
CalculationPair.Calculate<TReult>()
function? - How to specify TResult as an [out] parameter in the
CalculationPair.Calculate<TReult>()
function? - How to persist the calculation Expression and retrieve it later?