aboutsummaryrefslogtreecommitdiffstatsci
path: root/Samples/AnimTest/MiscUtil/ExpressionUtil.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Samples/AnimTest/MiscUtil/ExpressionUtil.cs')
-rw-r--r--Samples/AnimTest/MiscUtil/ExpressionUtil.cs99
1 files changed, 99 insertions, 0 deletions
diff --git a/Samples/AnimTest/MiscUtil/ExpressionUtil.cs b/Samples/AnimTest/MiscUtil/ExpressionUtil.cs
new file mode 100644
index 00000000..8f9ca4e6
--- /dev/null
+++ b/Samples/AnimTest/MiscUtil/ExpressionUtil.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Linq.Expressions;
+
+namespace MiscUtil.Linq
+{
+ /// <summary>
+ /// General purpose Expression utilities
+ /// </summary>
+ public static class ExpressionUtil
+ {
+ /// <summary>
+ /// Create a function delegate representing a unary operation
+ /// </summary>
+ /// <typeparam name="TArg1">The parameter type</typeparam>
+ /// <typeparam name="TResult">The return type</typeparam>
+ /// <param name="body">Body factory</param>
+ /// <returns>Compiled function delegate</returns>
+ public static Func<TArg1, TResult> CreateExpression<TArg1, TResult>(
+ Func<Expression, UnaryExpression> body)
+ {
+ ParameterExpression inp = Expression.Parameter(typeof(TArg1), "inp");
+ try
+ {
+ return Expression.Lambda<Func<TArg1, TResult>>(body(inp), inp).Compile();
+ }
+ catch (Exception ex)
+ {
+ string msg = ex.Message; // avoid capture of ex itself
+ return delegate { throw new InvalidOperationException(msg); };
+ }
+ }
+
+ /// <summary>
+ /// Create a function delegate representing a binary operation
+ /// </summary>
+ /// <typeparam name="TArg1">The first parameter type</typeparam>
+ /// <typeparam name="TArg2">The second parameter type</typeparam>
+ /// <typeparam name="TResult">The return type</typeparam>
+ /// <param name="body">Body factory</param>
+ /// <returns>Compiled function delegate</returns>
+ public static Func<TArg1, TArg2, TResult> CreateExpression<TArg1, TArg2, TResult>(
+ Func<Expression, Expression, BinaryExpression> body)
+ {
+ return CreateExpression<TArg1, TArg2, TResult>(body, false);
+ }
+
+ /// <summary>
+ /// Create a function delegate representing a binary operation
+ /// </summary>
+ /// <param name="castArgsToResultOnFailure">
+ /// 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.
+ /// </param>
+ /// <typeparam name="TArg1">The first parameter type</typeparam>
+ /// <typeparam name="TArg2">The second parameter type</typeparam>
+ /// <typeparam name="TResult">The return type</typeparam>
+ /// <param name="body">Body factory</param>
+ /// <returns>Compiled function delegate</returns>
+ public static Func<TArg1, TArg2, TResult> CreateExpression<TArg1, TArg2, TResult>(
+ Func<Expression, Expression, BinaryExpression> body, bool castArgsToResultOnFailure)
+ {
+ ParameterExpression lhs = Expression.Parameter(typeof(TArg1), "lhs");
+ ParameterExpression rhs = Expression.Parameter(typeof(TArg2), "rhs");
+ try
+ {
+ try
+ {
+ return Expression.Lambda<Func<TArg1, TArg2, TResult>>(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<Func<TArg1, TArg2, TResult>>(
+ 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); };
+ }
+ }
+ }
+} \ No newline at end of file