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); };
}
}
}
}