예제 #1
0
        /// <summary>
        /// Combines two given selectors by merging their member bindings.
        /// </summary>
        /// <typeparam name="TSource">The type of the selector's source parameter.</typeparam>
        /// <typeparam name="TResult">The type of the selector's result parameter.</typeparam>
        /// <param name="left">The first selector expression to combine.</param>
        /// <param name="right">The second selector expression to combine.</param>
        /// <returns>A single combined selector expression.</returns>
        public static Expression <Func <TSource, TResult> > Apply <TSource, TResult>(this Expression <Func <TSource, TResult> > left, Expression <Func <TSource, TResult> > right)
        {
            if (left == null)
            {
                throw new ArgumentNullException(nameof(left));
            }
            if (right == null)
            {
                throw new ArgumentNullException(nameof(right));
            }

            var leftInit  = left.Body as MemberInitExpression;
            var rightInit = right.Body as MemberInitExpression;

            if (leftInit == null || rightInit == null)
            {
                throw new NotSupportedException("Only member init expressions are supported yet.");
            }
            if (leftInit.NewExpression.Arguments.Any() || rightInit.NewExpression.Arguments.Any())
            {
                throw new NotSupportedException("Only parameterless constructors are supported yet.");
            }

            var l = left.Parameters[0];
            var r = right.Parameters[0];

            var binder   = new ParameterBinder(l, r);
            var bindings = leftInit.Bindings.Concat(rightInit.Bindings);

            return(Expression.Lambda <Func <TSource, TResult> >(
                       binder.Visit(Expression.MemberInit(Expression.New(typeof(TResult)), bindings)), r));
        }
예제 #2
0
        /// <inheritdoc />
        protected override Expression VisitMember(MemberExpression node)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            var property = node.Member as PropertyInfo;

            if (property?.GetMethod() != null && property.SetMethod() == null)
            {
                // cache "meta-data" for performance reasons
                var data = cache.GetOrAdd(property, _ => InjectLambdaMetadata.Create(property));

                if (ShouldInject(property, data))
                {
                    var lambda = data.Lambda(null);

                    // only one parameter for property getter
                    var argument = lambda.Parameters.Single();

                    // rebind expression for single (!) lambda argument
                    var binder = new ParameterBinder(argument, node.Expression);

                    return(Visit(binder.Visit(lambda.Body)));
                }
            }

            return(base.VisitMember(node));
        }
예제 #3
0
        /// <summary>
        /// Translates a given selector for a given subtype using it's source parameter.
        /// </summary>
        /// <typeparam name="V">The type of the translated selector's source parameter.</typeparam>
        /// <returns>A translated selector expression.</returns>
        public Expression <Func <V, U> > Source <V>()
            where V : T
        {
            var t = selector.Parameters[0];
            var v = Expression.Parameter(typeof(V), t.Name);

            var binder = new ParameterBinder(t, v);

            return(Expression.Lambda <Func <V, U> >(
                       binder.Visit(selector.Body), v));
        }
예제 #4
0
        /// <summary>
        /// Translates a given predicate for a given subtype.
        /// </summary>
        /// <typeparam name="TTranslatedSource">The type of the translated predicate's parameter.</typeparam>
        /// <returns>A translated predicate expression.</returns>
        public Expression <Func <TTranslatedSource, bool> > To <TTranslatedSource>()
            where TTranslatedSource : TSource
        {
            var s = predicate.Parameters[0];
            var t = Expression.Parameter(typeof(TTranslatedSource), s.Name);

            var binder = new ParameterBinder(s, t);

            return(Expression.Lambda <Func <TTranslatedSource, bool> >(
                       binder.Visit(predicate.Body), t));
        }
예제 #5
0
        /// <summary>
        /// Translates a given predicate for a given subtype.
        /// </summary>
        /// <typeparam name="U">The type of the translated predicate's parameter.</typeparam>
        /// <returns>A translated predicate expression.</returns>
        public Expression <Func <U, bool> > To <U>()
            where U : T
        {
            var t = predicate.Parameters[0];
            var u = Expression.Parameter(typeof(U), t.Name);

            var binder = new ParameterBinder(t, u);

            return(Expression.Lambda <Func <U, bool> >(
                       binder.Visit(predicate.Body), u));
        }
예제 #6
0
        /// <summary>
        /// Translates a given selector for a given subtype using it's source parameter.
        /// </summary>
        /// <typeparam name="TTranslatedSource">The type of the translated selector's source parameter.</typeparam>
        /// <returns>A translated selector expression.</returns>
        public Expression <Func <TTranslatedSource, TResult> > Source <TTranslatedSource>()
            where TTranslatedSource : TSource
        {
            var s = selector.Parameters[0];
            var t = Expression.Parameter(typeof(TTranslatedSource), s.Name);

            var binder = new ParameterBinder(s, t);

            return(Expression.Lambda <Func <TTranslatedSource, TResult> >(
                       binder.Visit(selector.Body), t));
        }
예제 #7
0
        /// <summary>
        /// Translates a given predicate for a given related type.
        /// </summary>
        /// <typeparam name="U">The type of the translated predicate's parameter.</typeparam>
        /// <param name="translation">The translation from the desired type to the given type,
        /// using the initially given predicate to be injected into a new predicate.</param>
        /// <returns>A translated predicate expression.</returns>
        public Expression <Func <U, bool> > To <U>(Expression <Func <U, Func <T, bool>, bool> > translation)
        {
            if (translation == null)
            {
                throw new ArgumentNullException(nameof(translation));
            }

            var u = translation.Parameters[0];
            var p = translation.Parameters[1];

            var binder = new ParameterBinder(p, predicate);

            return(Expression.Lambda <Func <U, bool> >(
                       binder.Visit(translation.Body), u));
        }
예제 #8
0
        /// <summary>
        /// Translates a given predicate for a given related type.
        /// </summary>
        /// <typeparam name="TTranslatedSource">The type of the translated predicate's parameter.</typeparam>
        /// <param name="translation">The translation from the desired type to the given type,
        /// using the initially given predicate to be injected into a new predicate.</param>
        /// <returns>A translated predicate expression.</returns>
        public Expression <Func <TTranslatedSource, bool> > To <TTranslatedSource>(Expression <Func <TTranslatedSource, Func <TSource, bool>, bool> > translation)
        {
            if (translation == null)
            {
                throw new ArgumentNullException(nameof(translation));
            }

            var t = translation.Parameters[0];
            var s = translation.Parameters[1];

            var binder = new ParameterBinder(s, predicate);

            return(Expression.Lambda <Func <TTranslatedSource, bool> >(
                       binder.Visit(translation.Body), t));
        }
예제 #9
0
        /// <summary>
        /// Translates a given predicate for a given related type.
        /// </summary>
        /// <typeparam name="TTranslatedSource">The type of the translated predicate's parameter.</typeparam>
        /// <param name="path">The path from the desired type to the given type.</param>
        /// <returns>A translated predicate expression.</returns>
        public Expression <Func <TTranslatedSource, bool> > To <TTranslatedSource>(Expression <Func <TTranslatedSource, TSource> > path)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            var s = predicate.Parameters[0];
            var t = path.Parameters[0];

            var binder = new ParameterBinder(s, path.Body);

            return(Expression.Lambda <Func <TTranslatedSource, bool> >(
                       binder.Visit(predicate.Body), t));
        }
예제 #10
0
        /// <summary>
        /// Translates a given selector for a given related type using it's source parameter.
        /// </summary>
        /// <typeparam name="V">The type of the translated selector's source parameter.</typeparam>
        /// <param name="translation">The translation from the desired type to the given type,
        /// using the initially given selector to be injected into a new selector.</param>
        /// <returns>A translated selector expression.</returns>
        public Expression <Func <V, U> > Source <V>(Expression <Func <V, Func <T, U>, U> > translation)
        {
            if (translation == null)
            {
                throw new ArgumentNullException(nameof(translation));
            }

            var v = translation.Parameters[0];
            var s = translation.Parameters[1];

            var binder = new ParameterBinder(s, selector);

            return(Expression.Lambda <Func <V, U> >(
                       binder.Visit(translation.Body), v));
        }
예제 #11
0
        /// <summary>
        /// Translates a given selector for a given related type using it's source parameter.
        /// </summary>
        /// <typeparam name="V">The type of the translated selector's source parameter.</typeparam>
        /// <param name="path">The path from the desired type to the given type.</param>
        /// <returns>A translated selector expression.</returns>
        public Expression <Func <V, U> > Source <V>(Expression <Func <V, T> > path)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            var t = selector.Parameters[0];
            var v = path.Parameters[0];

            var binder = new ParameterBinder(t, path.Body);

            return(Expression.Lambda <Func <V, U> >(
                       binder.Visit(selector.Body), v));
        }
예제 #12
0
        /// <summary>
        /// Translates a given predicate for a given related type.
        /// </summary>
        /// <typeparam name="U">The type of the translated predicate's parameter.</typeparam>
        /// <param name="path">The path from the desired type to the given type.</param>
        /// <returns>A translated predicate expression.</returns>
        public Expression <Func <U, bool> > To <U>(Expression <Func <U, T> > path)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            var t = predicate.Parameters[0];
            var u = path.Parameters[0];

            var binder = new ParameterBinder(t, path.Body);

            return(Expression.Lambda <Func <U, bool> >(
                       binder.Visit(predicate.Body), u));
        }
예제 #13
0
        /// <summary>
        /// Translates a given selector for a given related type using it's source parameter.
        /// </summary>
        /// <typeparam name="TTranslatedSource">The type of the translated selector's source parameter.</typeparam>
        /// <param name="translation">The translation from the desired type to the given type,
        /// using the initially given selector to be injected into a new selector.</param>
        /// <returns>A translated selector expression.</returns>
        public Expression <Func <TTranslatedSource, IEnumerable <TResult> > > Source <TTranslatedSource>(Expression <Func <TTranslatedSource, Func <TSource, TResult>, IEnumerable <TResult> > > translation)
        {
            if (translation == null)
            {
                throw new ArgumentNullException(nameof(translation));
            }

            var t = translation.Parameters[0];
            var s = translation.Parameters[1];

            var binder = new ParameterBinder(s, selector);

            return(Expression.Lambda <Func <TTranslatedSource, IEnumerable <TResult> > >(
                       binder.Visit(translation.Body), t));
        }
예제 #14
0
        /// <summary>
        /// Translates a given selector for a given related type using it's source parameter.
        /// </summary>
        /// <typeparam name="TTranslatedSource">The type of the translated selector's source parameter.</typeparam>
        /// <param name="path">The path from the desired type to the given type.</param>
        /// <returns>A translated selector expression.</returns>
        public Expression <Func <TTranslatedSource, TResult> > Source <TTranslatedSource>(Expression <Func <TTranslatedSource, TSource> > path)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            var s = selector.Parameters[0];
            var t = path.Parameters[0];

            var binder = new ParameterBinder(s, path.Body);

            return(Expression.Lambda <Func <TTranslatedSource, TResult> >(
                       binder.Visit(selector.Body), t));
        }
예제 #15
0
        /// <summary>
        /// Translates a given selector for a given related type using it's result parameter.
        /// </summary>
        /// <typeparam name="TTranslatedResult">The type of the translated selector's result parameter.</typeparam>
        /// <param name="translation">The translation from the desired type to the given type,
        /// using the initially given selector to be injected into a new selector.</param>
        /// <returns>A translated selector expression.</returns>
        public Expression <Func <TSource, TTranslatedResult> > Result <TTranslatedResult>(Expression <Func <TSource, Func <TSource, TResult>, TTranslatedResult> > translation)
        {
            if (translation is null)
            {
                throw new ArgumentNullException(nameof(translation));
            }

            var s = translation.Parameters[0];
            var t = translation.Parameters[1];

            var binder = new ParameterBinder(t, selector);

            return(Expression.Lambda <Func <TSource, TTranslatedResult> >(
                       binder.Visit(translation.Body), s));
        }
예제 #16
0
        /// <summary>
        /// Translates a given selector for a given related type using it's source and result parameter
        /// and combines it with another given selector by merging their member bindings.
        /// </summary>
        /// <typeparam name="V">The type of the translated selector's source parameter.</typeparam>
        /// <typeparam name="W">The type of the translated selector's result parameter.</typeparam>
        /// <param name="translation">The translation from the desired type to the given type,
        /// using the initially given selector to be injected into a new selector.</param>
        /// <param name="value">The additional selector expression to combine.</param>
        /// <returns>A single translated and combined selector expression.</returns>
        public Expression <Func <V, W> > To <V, W>(Expression <Func <V, Func <T, U>, W> > translation, Expression <Func <V, W> > value = null)
        {
            if (translation == null)
            {
                throw new ArgumentNullException(nameof(translation));
            }

            var v = translation.Parameters[0];
            var s = translation.Parameters[1];

            var binder = new ParameterBinder(s, selector);

            var result = Expression.Lambda <Func <V, W> >(
                binder.Visit(translation.Body), v);

            return(value != null?result.Apply(value) : result);
        }
예제 #17
0
        /// <summary>
        /// Translates a given selector for a given related type using it's source and result parameter
        /// and combines it with another given selector by merging their member bindings.
        /// </summary>
        /// <typeparam name="TTranslatedSource">The type of the translated selector's source parameter.</typeparam>
        /// <typeparam name="TTranslatedResult">The type of the translated selector's result parameter.</typeparam>
        /// <param name="translation">The translation from the desired type to the given type,
        /// using the initially given selector to be injected into a new selector.</param>
        /// <param name="value">The additional selector expression to combine.</param>
        /// <returns>A single translated and combined selector expression.</returns>
        public Expression <Func <TTranslatedSource, TTranslatedResult> > To <TTranslatedSource, TTranslatedResult>(Expression <Func <TTranslatedSource, Func <TSource, TResult>, TTranslatedResult> > translation, Expression <Func <TTranslatedSource, TTranslatedResult> > value = null)
        {
            if (translation == null)
            {
                throw new ArgumentNullException(nameof(translation));
            }

            var s = translation.Parameters[0];
            var t = translation.Parameters[1];

            var binder = new ParameterBinder(t, selector);

            var result = Expression.Lambda <Func <TTranslatedSource, TTranslatedResult> >(
                binder.Visit(translation.Body), s);

            return(value != null?result.Apply(value) : result);
        }
예제 #18
0
        /// <summary>
        /// Combines two given predicates using a conditional OR operation.
        /// </summary>
        /// <typeparam name="TSource">The type of the predicate's parameter.</typeparam>
        /// <param name="left">The first predicate expression to combine.</param>
        /// <param name="right">The second predicate expression to combine.</param>
        /// <returns>A single combined predicate expression.</returns>
        public static Expression <Func <TSource, bool> > Or <TSource>(this Expression <Func <TSource, bool> > left, Expression <Func <TSource, bool> > right)
        {
            if (left == null)
            {
                throw new ArgumentNullException(nameof(left));
            }
            if (right == null)
            {
                throw new ArgumentNullException(nameof(right));
            }

            var l = left.Parameters[0];
            var r = right.Parameters[0];

            var binder = new ParameterBinder(l, r);

            return(Expression.Lambda <Func <TSource, bool> >(
                       Expression.OrElse(binder.Visit(left.Body), right.Body), r));
        }