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