using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
public bool Check { get;set; }
public string Extra { get;set; }
public static void Main()
Expression<Func<string,SomeClass>> expr = e => new SomeClass { Check = e is string };
var merged = expr.Merge(a => new SomeClass { Extra = "Merged" }).Compile();
var result = merged.Invoke("test");
Console.WriteLine(result.Check);
public static class LinqSelectMergeExtension
public static Expression<Func<TSource, TExtendedDest>> Merge<TSource, TBaseDest, TExtendedDest>(
this Expression<Func<TSource, TBaseDest>> baseExpression,
Expression<Func<TSource, TExtendedDest>> mergeExpression)
var visitor = new MergingVisitor<TSource, TBaseDest, TExtendedDest>(baseExpression);
return (Expression<Func<TSource, TExtendedDest>>)visitor.Visit(mergeExpression);
private class MergingVisitor<TSource, TBaseDest, TExtendedDest> : ExpressionVisitor
private class LambdaRebindingVisitor : ExpressionVisitor
private ParameterExpression newParameter;
private ParameterExpression oldParameter;
public LambdaRebindingVisitor(ParameterExpression newParameter,
ParameterExpression oldParameter)
this.newParameter = newParameter;
this.oldParameter = oldParameter;
protected override Expression VisitMember(MemberExpression node)
if (node.Expression == oldParameter)
return Expression.MakeMemberAccess(newParameter, node.Member);
return base.VisitMember(node);
protected override Expression VisitConditional(ConditionalExpression node)
return base.VisitConditional(node);
protected override Expression VisitTypeBinary(TypeBinaryExpression node)
if (node.Expression == oldParameter)
case ExpressionType.TypeIs:
return Expression.TypeIs(newParameter, node.TypeOperand);
return base.VisitTypeBinary(node);
private MemberInitExpression baseInit;
private ParameterExpression baseParameter;
private ParameterExpression newParameter;
public MergingVisitor(Expression<Func<TSource, TBaseDest>> baseExpression)
var lambda = (LambdaExpression)baseExpression;
baseInit = (MemberInitExpression)lambda.Body;
baseParameter = lambda.Parameters[0];
protected override Expression VisitLambda<T>(Expression<T> node)
if (newParameter == null)
newParameter = node.Parameters[0];
return base.VisitLambda<T>(node);
protected override Expression VisitMemberInit(MemberInitExpression node)
LambdaRebindingVisitor rebindVisitor =
new LambdaRebindingVisitor(newParameter, baseParameter);
var reboundBaseInit = (MemberInitExpression)rebindVisitor.Visit(baseInit);
var mergedInitList = node.Bindings.ToList();
foreach (var binding in reboundBaseInit.Bindings)
var existing = mergedInitList.Any(a => a.Member.Name == binding.Member.Name);
mergedInitList.Add(binding);
return Expression.MemberInit(Expression.New(typeof(TExtendedDest)),