using System; using System.Linq.Expressions; namespace MiscUtil.Linq { /// /// General purpose Expression utilities /// public static class ExpressionUtil { /// /// Create a function delegate representing a unary operation /// /// The parameter type /// The return type /// Body factory /// Compiled function delegate public static Func CreateExpression( Func body) { ParameterExpression inp = Expression.Parameter(typeof(TArg1), "inp"); try { return Expression.Lambda>(body(inp), inp).Compile(); } catch (Exception ex) { string msg = ex.Message; // avoid capture of ex itself return delegate { throw new InvalidOperationException(msg); }; } } /// /// Create a function delegate representing a binary operation /// /// The first parameter type /// The second parameter type /// The return type /// Body factory /// Compiled function delegate public static Func CreateExpression( Func body) { return CreateExpression(body, false); } /// /// Create a function delegate representing a binary operation /// /// /// If no matching operation is possible, attempt to convert /// TArg1 and TArg2 to TResult for a match? For example, there is no /// "decimal operator /(decimal, int)", but by converting TArg2 (int) to /// TResult (decimal) a match is found. /// /// The first parameter type /// The second parameter type /// The return type /// Body factory /// Compiled function delegate public static Func CreateExpression( Func body, bool castArgsToResultOnFailure) { ParameterExpression lhs = Expression.Parameter(typeof(TArg1), "lhs"); ParameterExpression rhs = Expression.Parameter(typeof(TArg2), "rhs"); try { try { return Expression.Lambda>(body(lhs, rhs), lhs, rhs).Compile(); } catch (InvalidOperationException) { if (castArgsToResultOnFailure && !( // if we show retry typeof(TArg1) == typeof(TResult) && // and the args aren't typeof(TArg2) == typeof(TResult))) { // already "TValue, TValue, TValue"... // convert both lhs and rhs to TResult (as appropriate) Expression castLhs = typeof(TArg1) == typeof(TResult) ? (Expression)lhs : (Expression)Expression.Convert(lhs, typeof(TResult)); Expression castRhs = typeof(TArg2) == typeof(TResult) ? (Expression)rhs : (Expression)Expression.Convert(rhs, typeof(TResult)); return Expression.Lambda>( body(castLhs, castRhs), lhs, rhs).Compile(); } else throw; } } catch (Exception ex) { string msg = ex.Message; // avoid capture of ex itself return delegate { throw new InvalidOperationException(msg); }; } } } }