public static IQueryable<Package> Search(this IQueryable<Package> source, string searchTerm) { // Split the search terms by spaces var terms = (searchTerm ?? String.Empty).Split(); // Build a list of expressions for each term var expressions = new List<LambdaExpression>(); foreach (var criteria in searchCriteria) { foreach (var term in terms) { expressions.Add(criteria(term)); } } // Build a giant or statement using the bodies of the lambdas var body = expressions.Select(p => p.Body) .Aggregate(Expression.OrElse); // Now build the final predicate var parameterExpr = Expression.Parameter(typeof(Package)); // Fix up the body to use our parameter expression body = new ParameterExpressionReplacer(parameterExpr).Visit(body); // Build the final predicate var predicate = Expression.Lambda<Func<Package, bool>>(body, parameterExpr); // Apply it to the query return source.Where(predicate); }
protected Expression CreateAdaptToExpression(Expression source, Expression destination, CompileArgument arg) { if (destination == null) { return(CreateAdaptExpression(source, arg.DestinationType, arg)); } if (source.Type == destination.Type && arg.Settings.ShallowCopyForSameType == true) { return(source); } //adapt(source, dest); var lambda = arg.Context.Config.CreateInlineMapExpression(source.Type, destination.Type, arg.MapType, arg.Context); var exp = lambda.Apply(source, destination); //transform(adapt(source, dest)); if (arg.Settings.DestinationTransforms.Transforms.ContainsKey(exp.Type)) { var transform = arg.Settings.DestinationTransforms.Transforms[exp.Type]; var replacer = new ParameterExpressionReplacer(transform.Parameters, exp); var newExp = replacer.Visit(transform.Body); exp = replacer.ReplaceCount >= 2 ? Expression.Invoke(transform, exp) : newExp; } return(exp.To(destination.Type)); }
public static Expression <Func <TTarget, bool> > ConvertTo <TSource, TTarget>(this Expression <Func <TSource, bool> > source, Expression <Func <TTarget, TSource> > sourceSelector) { var body = new ParameterExpressionReplacer { source = source.Parameters[0], target = sourceSelector.Body }.Visit(source.Body); var lambda = Expression.Lambda <Func <TTarget, bool> >(body, sourceSelector.Parameters); return(lambda); }
private Expression <Func <StoredEntry, bool> > TranslatePredicate(Expression <Func <IEntryState <TId, TData>, bool> > predicate) { Assert(predicate != null); var parameter = Expression.Parameter(typeof(StoredEntry)); var body = ParameterExpressionReplacer.ReplaceParameter(predicate.Body, predicate.Parameters.First(), parameter); return(Expression.Lambda <Func <StoredEntry, bool> >(body, parameter)); }
public static Expression <Func <TOuter, TResult> > Bind <TOuter, TInner, TResult>(this Expression <Func <TOuter, TInner> > source, Expression <Func <TInner, TResult> > resultSelector) { var body = new ParameterExpressionReplacer { source = resultSelector.Parameters[0], target = source.Body }.Visit(resultSelector.Body); var lambda = Expression.Lambda <Func <TOuter, TResult> >(body, source.Parameters); return(lambda); }
public static IQueryable <Package> Search(this IQueryable <Package> source, string searchTerm) { if (String.IsNullOrWhiteSpace(searchTerm)) { return(source); } // Split the search terms by spaces var terms = (searchTerm ?? String.Empty).Split(); // Build a list of expressions for each term var expressions = new List <LambdaExpression>(); foreach (var term in terms) { var localSearchTerm = term.to_lower(); if (localSearchTerm.StartsWith("id:")) { expressions.Add(idCriteria(localSearchTerm.Replace("id:", string.Empty))); } if (localSearchTerm.StartsWith("author:")) { expressions.Add(authorCriteria(localSearchTerm.Replace("author:", string.Empty))); } else if (localSearchTerm.StartsWith("tag:")) { expressions.Add(tagCriteria(localSearchTerm.Replace("tag:", string.Empty))); } else { foreach (var criteria in searchCriteria) { expressions.Add(criteria(localSearchTerm)); } } } //todo this becomes an AND // Build a giant or statement using the bodies of the lambdas var body = expressions.Select(p => p.Body) .Aggregate(Expression.OrElse); // Now build the final predicate var parameterExpr = Expression.Parameter(typeof(Package)); // Fix up the body to use our parameter expression body = new ParameterExpressionReplacer(parameterExpr).Visit(body); // Build the final predicate var predicate = Expression.Lambda <Func <Package, bool> >(body, parameterExpr); // Apply it to the query return(source.Where(predicate)); }
private Expression <TDelegate> ConvertExpression <TDelegate>(LambdaExpression expression) where TDelegate : Delegate { var parameter = expression.Parameters.First(); var body = expression.Body; var newParameter = Expression.Parameter(typeof(TRemote)); var newBody = ParameterExpressionReplacer.ReplaceParameter(body, parameter, newParameter); return(Expression.Lambda <TDelegate>(newBody, newParameter)); }
public static IQueryable<Package> Search(this IQueryable<Package> source, string searchTerm) { if (String.IsNullOrWhiteSpace(searchTerm)) { return source; } // Split the search terms by spaces var terms = (searchTerm ?? String.Empty).Split(); // Build a list of expressions for each term var expressions = new List<LambdaExpression>(); foreach (var term in terms) { var localSearchTerm = term.to_lower(); if (localSearchTerm.StartsWith("id:")) { expressions.Add(idCriteria(localSearchTerm.Replace("id:", string.Empty))); } if (localSearchTerm.StartsWith("author:")) { expressions.Add(authorCriteria(localSearchTerm.Replace("author:", string.Empty))); } else if (localSearchTerm.StartsWith("tag:")) { expressions.Add(tagCriteria(localSearchTerm.Replace("tag:", string.Empty))); } else { foreach (var criteria in searchCriteria) { expressions.Add(criteria(localSearchTerm)); } } } //todo this becomes an AND // Build a giant or statement using the bodies of the lambdas var body = expressions.Select(p => p.Body) .Aggregate(Expression.OrElse); // Now build the final predicate var parameterExpr = Expression.Parameter(typeof(Package)); // Fix up the body to use our parameter expression body = new ParameterExpressionReplacer(parameterExpr).Visit(body); // Build the final predicate var predicate = Expression.Lambda<Func<Package, bool>>(body, parameterExpr); // Apply it to the query return source.Where(predicate); }
public static Expression <Func <TSource, bool> > And <TSource>(this Expression <Func <TSource, bool> > a, Expression <Func <TSource, bool> > b) { Type typeFromHandle = typeof(TSource); ParameterExpression parameterExpression = Expression.Parameter(typeFromHandle, "root"); Expression left = ParameterExpressionReplacer.Replace(a.Body, parameterExpression); Expression right = ParameterExpressionReplacer.Replace(b.Body, parameterExpression); BinaryExpression body = Expression.And(left, right); return(Expression.Lambda <Func <TSource, bool> >(body, new ParameterExpression[] { parameterExpression })); }
private static Expression <Func <TEntry, bool> > BuildPredicate <TEntry>(TEntry comparand, Expression <Func <TEntry, TEntry, bool> > equalityComparer) { Assert(comparand != null); Assert(equalityComparer != null); var idSelector = DataPropertyHelper.BuildPredicate(comparand); var comparandConstant = Expression.Constant(comparand, typeof(TEntry)); var parameter = equalityComparer.Parameters.First(); var equality = ParameterExpressionReplacer.ReplaceParameter(equalityComparer.Body, equalityComparer.Parameters.Last(), comparandConstant); var idEquality = ParameterExpressionReplacer.ReplaceParameter(idSelector.Body, idSelector.Parameters.First(), parameter); var body = Expression.AndAlso(idEquality, equality); return(Expression.Lambda <Func <TEntry, bool> >(body, parameter)); }
protected Expression CreateAdaptExpression(Expression source, Type destinationType, CompileArgument arg) { if (source.Type == destinationType && (arg.Settings.ShallowCopyForSameType == true || arg.MapType == MapType.Projection)) return source.To(destinationType); var lambda = arg.Context.Config.CreateInlineMapExpression(source.Type, destinationType, arg.MapType, arg.Context); var exp = lambda.Apply(source); if (arg.Settings.DestinationTransforms.Transforms.ContainsKey(exp.Type)) { var transform = arg.Settings.DestinationTransforms.Transforms[exp.Type]; var replacer = new ParameterExpressionReplacer(transform.Parameters, exp); var newExp = replacer.Visit(transform.Body); exp = replacer.ReplaceCount >= 2 ? Expression.Invoke(transform, exp) : newExp; } return exp.To(destinationType); }
public static Expression <Func <TDataRepresentation, bool> > TranslatePredicate <TId, TData, TDataRepresentation>(Expression <Func <TData, bool> > predicate) where TData : class where TDataRepresentation : class, IDataRepresentation <TId, TData> { // The resulting predicate checks // 1) If the entry's payload matches the specified predicate. // 2) If the entry's data is not null (The entry is not deleted) var parameter = Expression.Parameter(typeof(TDataRepresentation)); var dataAccessor = DataHelper <TId, TData> .Accessor; var nullConstant = DataHelper <TId, TData> .Null; var data = ParameterExpressionReplacer.ReplaceParameter(dataAccessor.Body, dataAccessor.Parameters.First(), parameter); var isNull = Expression.ReferenceEqual(data, nullConstant); var isNotNull = Expression.Not(isNull); var matchesPredicate = ParameterExpressionReplacer.ReplaceParameter(predicate.Body, predicate.Parameters.First(), data); var body = Expression.AndAlso(isNotNull, matchesPredicate); return(Expression.Lambda <Func <TDataRepresentation, bool> >(body, parameter)); }
public static LambdaExpression And(this LambdaExpression a, LambdaExpression b) { if (a == null) { return(b); } if (b == null) { return(a); } Type rootType = a.Parameters[0].Type; var memberParam = Expression.Parameter(rootType, "root"); var aNewBody = ParameterExpressionReplacer.Replace(a.Body, memberParam); var bNewBody = ParameterExpressionReplacer.Replace(b.Body, memberParam); var newBody = Expression.And(aNewBody, bNewBody); var lambda = Expression.Lambda(a.Type, newBody, memberParam); return(lambda); }
private static Expression <Func <TEntry, TEntry, bool> > BuildEqualityComparer <TEntry, TVersion>(Expression <Func <TEntry, TVersion> > versionSelector) where TEntry : class where TVersion : IEquatable <TVersion> { Assert(versionSelector != null); var param1 = Expression.Parameter(typeof(TEntry), "left"); var param2 = Expression.Parameter(typeof(TEntry), "right"); var version1 = ParameterExpressionReplacer.ReplaceParameter(versionSelector.Body, versionSelector.Parameters.First(), param1); var version2 = ParameterExpressionReplacer.ReplaceParameter(versionSelector.Body, versionSelector.Parameters.First(), param2); var equalityMethod = typeof(IEquatable <TVersion>).GetMethod(nameof(Equals)); Assert(equalityMethod != null); var call = Expression.Call(version1, equalityMethod, version2); Expression equality; if (typeof(TVersion).IsValueType) { equality = call; } else // (left == null && right == null) || (left != null && right != null && left.Equals(right)); { var isNull1 = Expression.Equal(version1, Expression.Constant(null, typeof(TVersion))); var isNull2 = Expression.Equal(version2, Expression.Constant(null, typeof(TVersion))); var isNotNull1 = Expression.Not(isNull1); var isNotNull2 = Expression.Not(isNull2); var bothNull = Expression.AndAlso(isNull1, isNull2); var bothNotNUll = Expression.AndAlso(isNotNull1, isNotNull2); equality = Expression.OrElse(bothNull, Expression.AndAlso(bothNotNUll, call)); } return(Expression.Lambda <Func <TEntry, TEntry, bool> >(equality, param1, param2)); }
public static IQueryable <Package> Search(this IQueryable <Package> source, string searchTerm) { if (String.IsNullOrWhiteSpace(searchTerm)) { return(source); } // Split the search terms by spaces var terms = searchTerm.Split(); // Build a list of expressions for each term var expressions = new List <LambdaExpression>(); foreach (var criteria in SearchCriteria) { foreach (var term in terms) { expressions.Add(criteria(term)); } } // Build a giant or statement using the bodies of the lambdas var body = expressions.Select(p => p.Body) .Aggregate(Expression.OrElse); // Now build the final predicate var parameterExpr = Expression.Parameter(typeof(Package)); // Fix up the body to use our parameter expression body = new ParameterExpressionReplacer(parameterExpr).Visit(body); // Build the final predicate var predicate = Expression.Lambda <Func <Package, bool> >(body, parameterExpr); // Apply it to the query return(source.Where(predicate)); }
protected Expression CreateBlockExpressionBody(Expression source, Expression destination, CompileArgument arg) { if (arg.MapType == MapType.Projection) throw new InvalidOperationException( $"Mapping is invalid for projection: TSource: {arg.SourceType} TDestination: {arg.DestinationType}"); var result = Expression.Variable(arg.DestinationType); Expression assign = Expression.Assign(result, destination ?? CreateInstantiationExpression(source, arg)); var set = CreateBlockExpression(source, result, arg); if (arg.Settings.AfterMappingFactories.Count > 0) { //var result = adapt(source); //action(source, result); var actions = new List<Expression> { set }; foreach (var afterMappingFactory in arg.Settings.AfterMappingFactories) { var afterMapping = afterMappingFactory(arg); var args = afterMapping.Parameters; Expression invoke; if (args[0].Type.IsReferenceAssignableFrom(source.Type) && args[1].Type.IsReferenceAssignableFrom(result.Type)) { var replacer = new ParameterExpressionReplacer(args, source, result); invoke = replacer.Visit(afterMapping.Body); } else { invoke = Expression.Invoke(afterMapping, source.To(args[0].Type), result.To(args[1].Type)); } actions.Add(invoke); } set = Expression.Block(actions); } if (arg.Settings.PreserveReference == true && !arg.SourceType.GetTypeInfo().IsValueType && !arg.DestinationType.GetTypeInfo().IsValueType) { //using (var scope = new MapContextScope()) { // var dict = scope.Context.Reference; // object cache; // if (dict.TryGetValue(source, out cache)) // result = (TDestination)cache; // else { // result = new TDestination(); // dict.Add(source, (object)result); // result.Prop1 = adapt(source.Prop1); // result.Prop2 = adapt(source.Prop2); // } //} var scope = Expression.Variable(typeof(MapContextScope)); var newScope = Expression.Assign(scope, Expression.New(typeof(MapContextScope))); var dict = Expression.Variable(typeof(Dictionary<object, object>)); var refContext = Expression.Property(scope, "Context"); var refDict = Expression.Property(refContext, "References"); var assignDict = Expression.Assign(dict, refDict); var refAdd = Expression.Call(dict, "Add", null, Expression.Convert(source, typeof(object)), Expression.Convert(result, typeof(object))); var setResultAndCache = Expression.Block(assign, refAdd, set); var cached = Expression.Variable(typeof(object)); var tryGetMethod = typeof(Dictionary<object, object>).GetMethod("TryGetValue", new[] { typeof(object), typeof(object).MakeByRefType() }); var checkHasRef = Expression.Call(dict, tryGetMethod, source, cached); var setResult = Expression.IfThenElse( checkHasRef, ExpressionEx.Assign(result, cached), setResultAndCache); var usingBody = Expression.Block(new[] { cached, dict }, assignDict, setResult); var dispose = Expression.Call(scope, "Dispose", null); set = Expression.Block(new[] { scope }, newScope, Expression.TryFinally(usingBody, dispose)); } else { set = Expression.Block(assign, set); } //TDestination result; //if (source == null) // result = default(TDestination); //else // result = adapt(source); //return result; if (!arg.SourceType.GetTypeInfo().IsValueType || arg.SourceType.IsNullable()) { var compareNull = Expression.Equal(source, Expression.Constant(null, source.Type)); set = Expression.IfThenElse( compareNull, Expression.Assign(result, destination ?? Expression.Constant(arg.DestinationType.GetDefault(), arg.DestinationType)), set); } return Expression.Block(new[] { result }, set, result); }
public static IQueryable <Package> Search(this IQueryable <Package> source, string searchTerm, bool lowerCaseExpression = true) { if (String.IsNullOrWhiteSpace(searchTerm)) { return(source); } // Split the search terms by spaces var terms = (searchTerm ?? String.Empty).Split(); var idSearch = searchTerm.to_lower().Contains("id:"); var authorSearch = searchTerm.to_lower().Contains("author:"); var tagSearch = searchTerm.to_lower().Contains("tag:"); // Build a list of expressions for each term var expressions = new List <LambdaExpression>(); foreach (var term in terms) { // doesn't matter if this is lowercased or not var localSearchTerm = term.to_lower().Replace("id:", string.Empty).Replace("author:", string.Empty).Replace("tag:", string.Empty); if (idSearch) { expressions.Add(lowerCaseExpression ? idLowerCriteria(localSearchTerm) : idCriteria(localSearchTerm) ); } else if (authorSearch) { expressions.Add(lowerCaseExpression ? authorLowerCriteria(localSearchTerm) : authorCriteria(localSearchTerm) ); } else if (tagSearch) { expressions.Add(lowerCaseExpression ? tagLowerCriteria(localSearchTerm) : tagCriteria(localSearchTerm) ); } else { var criteriaList = lowerCaseExpression ? searchLowerCriteria : searchCriteria; foreach (var criteria in criteriaList) { expressions.Add(criteria(localSearchTerm)); } } } //todo this becomes an AND // Build a giant or statement using the bodies of the lambdas var body = expressions.Select(p => p.Body) .Aggregate(Expression.OrElse); // Now build the final predicate var parameterExpr = Expression.Parameter(typeof(Package)); // Fix up the body to use our parameter expression body = new ParameterExpressionReplacer(parameterExpr).Visit(body); // Build the final predicate var predicate = Expression.Lambda <Func <Package, bool> >(body, parameterExpr); // Apply it to the query return(source.Where(predicate)); }
protected Expression CreateBlockExpressionBody(Expression source, Expression destination, CompileArgument arg) { if (arg.MapType == MapType.Projection) { throw new InvalidOperationException("Mapping is invalid for projection"); } //var result = new TDest(); var result = Expression.Variable(arg.DestinationType, "result"); var newObj = CreateInstantiationExpression(source, destination, arg); Expression assign = Expression.Assign(result, newObj); var set = CreateBlockExpression(source, result, arg); //result.prop = adapt(source.prop); //action(source, result); if (arg.Settings.AfterMappingFactories.Count > 0) { var actions = new List <Expression> { set }; foreach (var afterMappingFactory in arg.Settings.AfterMappingFactories) { var afterMapping = afterMappingFactory(arg); var args = afterMapping.Parameters; Expression invoke; if (args[0].Type.IsReferenceAssignableFrom(source.Type) && args[1].Type.IsReferenceAssignableFrom(result.Type)) { var replacer = new ParameterExpressionReplacer(args, source, result); invoke = replacer.Visit(afterMapping.Body); } else { invoke = Expression.Invoke(afterMapping, source.To(args[0].Type), result.To(args[1].Type)); } actions.Add(invoke); } set = Expression.Block(actions); } //using (var scope = new MapContextScope()) { // var references = scope.Context.Reference; // object cache; // if (references.TryGetValue(source, out cache)) // result = (TDestination)cache; // else { // result = new TDestination(); // references[source] = (object)result; // result.prop = adapt(source.prop); // } //} if (arg.Settings.PreserveReference == true && !arg.SourceType.GetTypeInfo().IsValueType&& !arg.DestinationType.GetTypeInfo().IsValueType) { var scope = Expression.Variable(typeof(MapContextScope), "scope"); var newScope = Expression.Assign(scope, Expression.New(typeof(MapContextScope))); var dictType = typeof(Dictionary <object, object>); var dict = Expression.Variable(dictType, "references"); var refContext = Expression.Property(scope, "Context"); var refDict = Expression.Property(refContext, "References"); var assignDict = Expression.Assign(dict, refDict); var indexer = dictType.GetProperties().First(item => item.GetIndexParameters().Length > 0); var refAssign = Expression.Assign( Expression.Property(dict, indexer, Expression.Convert(source, typeof(object))), Expression.Convert(result, typeof(object))); var setResultAndCache = Expression.Block(assign, refAssign, set); var cache = Expression.Variable(typeof(object), "cache"); var tryGetMethod = typeof(Dictionary <object, object>).GetMethod("TryGetValue", new[] { typeof(object), typeof(object).MakeByRefType() }); var checkHasRef = Expression.Call(dict, tryGetMethod, source, cache); var setResult = Expression.IfThenElse( checkHasRef, ExpressionEx.Assign(result, cache), setResultAndCache); var usingBody = Expression.Block(new[] { cache, dict }, assignDict, setResult); var dispose = Expression.Call(scope, "Dispose", null); set = Expression.Block(new[] { scope }, newScope, Expression.TryFinally(usingBody, dispose)); } else { set = Expression.Block(assign, set); } //TDestination result; //if (source == null) // result = default(TDestination); //else { // result = new TDestination(); // result.prop = adapt(source.prop); //} //return result; if (!arg.SourceType.GetTypeInfo().IsValueType || arg.SourceType.IsNullable()) { var compareNull = Expression.Equal(source, Expression.Constant(null, source.Type)); set = Expression.IfThenElse( compareNull, Expression.Assign(result, destination ?? Expression.Constant(arg.DestinationType.GetDefault(), arg.DestinationType)), set); } //var drvdSource = source as TDerivedSource //if (drvdSource != null) // result = adapt<TSource, TDest>(drvdSource); //else { // result = new TDestination(); // result.prop = adapt(source.prop); //} //return result; foreach (var tuple in arg.Settings.Includes) { //same type, no redirect to prevent endless loop if (tuple.Source == arg.SourceType) { continue; } //type is not compatible, no redirect if (!arg.SourceType.IsReferenceAssignableFrom(tuple.Source)) { continue; } var blocks = new List <Expression>(); var vars = new List <ParameterExpression>(); var drvdSource = Expression.Variable(tuple.Source); vars.Add(drvdSource); var drvdSourceAssign = Expression.Assign( drvdSource, Expression.TypeAs(source, tuple.Source)); blocks.Add(drvdSourceAssign); var cond = Expression.NotEqual(drvdSource, Expression.Constant(null, tuple.Source)); ParameterExpression drvdDest = null; if (destination != null) { drvdDest = Expression.Variable(tuple.Destination); vars.Add(drvdDest); var drvdDestAssign = Expression.Assign( drvdDest, Expression.TypeAs(destination, tuple.Destination)); blocks.Add(drvdDestAssign); cond = Expression.AndAlso( cond, Expression.NotEqual(drvdDest, Expression.Constant(null, tuple.Destination))); } var adaptExpr = drvdDest == null ? CreateAdaptExpression(drvdSource, tuple.Destination, arg) : CreateAdaptToExpression(drvdSource, drvdDest, arg); var adapt = Expression.Assign(result, adaptExpr); var ifExpr = Expression.Condition(cond, adapt, set, typeof(void)); blocks.Add(ifExpr); set = Expression.Block(vars, blocks); } return(Expression.Block(new[] { result }, set, result)); }
public static Expression Apply(this LambdaExpression lambda, params Expression[] exps) { var replacer = new ParameterExpressionReplacer(lambda.Parameters, exps); return replacer.Visit(lambda.Body); }
protected Expression CreateBlockExpressionBody(Expression source, Expression destination, CompileArgument arg) { if (arg.MapType == MapType.Projection) { throw new InvalidOperationException( $"Mapping is invalid for projection: TSource: {arg.SourceType} TDestination: {arg.DestinationType}"); } var result = Expression.Variable(arg.DestinationType); Expression assign = Expression.Assign(result, destination ?? CreateInstantiationExpression(source, arg)); var set = CreateBlockExpression(source, result, arg); if (arg.Settings.AfterMappingFactories.Count > 0) { //var result = adapt(source); //action(source, result); var actions = new List <Expression> { set }; foreach (var afterMappingFactory in arg.Settings.AfterMappingFactories) { var afterMapping = afterMappingFactory(arg); var args = afterMapping.Parameters; Expression invoke; if (args[0].Type.IsReferenceAssignableFrom(source.Type) && args[1].Type.IsReferenceAssignableFrom(result.Type)) { var replacer = new ParameterExpressionReplacer(args, source, result); invoke = replacer.Visit(afterMapping.Body); } else { invoke = Expression.Invoke(afterMapping, source.To(args[0].Type), result.To(args[1].Type)); } actions.Add(invoke); } set = Expression.Block(actions); } if (arg.Settings.PreserveReference == true && !arg.SourceType.GetTypeInfo().IsValueType&& !arg.DestinationType.GetTypeInfo().IsValueType) { //using (var scope = new MapContextScope()) { // var dict = scope.Context.Reference; // object cache; // if (dict.TryGetValue(source, out cache)) // result = (TDestination)cache; // else { // result = new TDestination(); // dict.Add(source, (object)result); // result.Prop1 = adapt(source.Prop1); // result.Prop2 = adapt(source.Prop2); // } //} var scope = Expression.Variable(typeof(MapContextScope)); var newScope = Expression.Assign(scope, Expression.New(typeof(MapContextScope))); var dict = Expression.Variable(typeof(Dictionary <object, object>)); var refContext = Expression.Property(scope, "Context"); var refDict = Expression.Property(refContext, "References"); var assignDict = Expression.Assign(dict, refDict); var refAdd = Expression.Call(dict, "Add", null, Expression.Convert(source, typeof(object)), Expression.Convert(result, typeof(object))); var setResultAndCache = Expression.Block(assign, refAdd, set); var cached = Expression.Variable(typeof(object)); var tryGetMethod = typeof(Dictionary <object, object>).GetMethod("TryGetValue", new[] { typeof(object), typeof(object).MakeByRefType() }); var checkHasRef = Expression.Call(dict, tryGetMethod, source, cached); var setResult = Expression.IfThenElse( checkHasRef, ExpressionEx.Assign(result, cached), setResultAndCache); var usingBody = Expression.Block(new[] { cached, dict }, assignDict, setResult); var dispose = Expression.Call(scope, "Dispose", null); set = Expression.Block(new[] { scope }, newScope, Expression.TryFinally(usingBody, dispose)); } else { set = Expression.Block(assign, set); } //TDestination result; //if (source == null) // result = default(TDestination); //else // result = adapt(source); //return result; if (!arg.SourceType.GetTypeInfo().IsValueType || arg.SourceType.IsNullable()) { var compareNull = Expression.Equal(source, Expression.Constant(null, source.Type)); set = Expression.IfThenElse( compareNull, Expression.Assign(result, destination ?? Expression.Constant(arg.DestinationType.GetDefault(), arg.DestinationType)), set); } return(Expression.Block(new[] { result }, set, result)); }