Đây là ví dụ về cả hai cách tiếp cận. Nếu tôi đã bỏ lỡ một cái gì đó, hoặc bạn muốn biết thêm thông tin, chỉ cần cho tôi biết.
static void Main()
{
// try to do "x + (3 * x)"
var single = BuildSingle<decimal>();
var composite = BuildComposite<decimal>();
Console.WriteLine("{0} vs {1}", single(13.2M), composite(13.2M));
}
// utility method to get the 3 as the correct type, since there is not always a "int x T"
static Expression ConvertConstant<TSource, TDestination>(TSource value)
{
return Expression.Convert(Expression.Constant(value, typeof(TSource)), typeof(TDestination));
}
// option 1: a single expression tree; this is the most efficient
static Func<T,T> BuildSingle<T>()
{
var param = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Add(param, Expression.Multiply(
ConvertConstant<int, T>(3), param));
var lambda = Expression.Lambda<Func<T, T>>(body, param);
return lambda.Compile();
}
// option 2: nested expression trees:
static Func<T, T> BuildComposite<T>()
{
// step 1: do the multiply:
var paramInner = Expression.Parameter(typeof(T), "inner");
Expression bodyInner = Expression.Multiply(
ConvertConstant<int, T>(3), paramInner);
var lambdaInner = Expression.Lambda(bodyInner, paramInner);
// step 2: do the add, invoking the existing tree
var paramOuter = Expression.Parameter(typeof(T), "outer");
Expression bodyOuter = Expression.Add(paramOuter, Expression.Invoke(lambdaInner, paramOuter));
var lambdaOuter = Expression.Lambda<Func<T, T>>(bodyOuter, paramOuter);
return lambdaOuter.Compile();
}
Cá nhân, tôi sẽ hướng tới phương pháp đầu tiên; nó đơn giản và hiệu quả hơn. Điều này có thể liên quan đến việc truyền tham số ban đầu trong suốt một chồng mã lồng nhau, nhưng cũng vậy. Tôi đã có một số mã ở đâu đó mà có cách tiếp cận "Gọi" (composite), và viết lại cây như cách tiếp cận đầu tiên (duy nhất) - nhưng nó khá phức tạp và lâu dài. Nhưng rất hữu ích cho Entity Framework (không hỗ trợ Expression.Invoke).
Nguồn
2008-12-06 22:21:42
Các ví dụ khác được thêm vào ... –