private Expression <Func <TType, IDiff, TType> > Compile() { ParameterExpression orig = Expression.Parameter(typeof(TType), "orig"); ParameterExpression diff = Expression.Parameter(typeof(IDiff), "diff"); ParameterExpression ret = Expression.Parameter(typeof(TType), "ret"); ParameterExpression item = Expression.Parameter(typeof(IDiffClassItem), "item"); return(Expression.Lambda <Func <TType, IDiff, TType> >( Expression.Block( new[] { ret }, Expression.Assign( ret, Expression.New(typeof(TType)) ), Expression.Block(Class <TType> .Properties.Select(property => Expression.Assign( Expression.Property(ret, property.ReflectionPropertyInfo), Expression.Property(orig, property.ReflectionPropertyInfo) ) )), ExpressionExtensions.ForEach( item, diff, Expression.IfThen( Expression.Not(Expression.TypeIs(item, typeof(IDiffItemUnchanged))), Expression.Block( Expression.Switch( Expression.Property( Expression.Property( item, DiffItemsMembers.ClassProperty() ), FastPropertyMembers.UniqueID() ), Expression.Throw( Expression.New(typeof(Exception)) ), Class <TType> .Properties.Select(property => this.EvaluateProperty(ret, orig, property, item)).ToArray() ) ) ) ), ret ), orig, diff )); }
private Expression EvaluateProperty(ParameterExpression leftEnumerator, ParameterExpression leftSomeLeft, ParameterExpression rightEnumerator, ParameterExpression rightSomeLeft, Expression conflicts, Expression ret, Property property) { Expression leftCurrent = Expression.Property(leftEnumerator, EnumerableMembers.Current(typeof(IDiffItem))); Expression rightCurrent = Expression.Property(rightEnumerator, EnumerableMembers.Current(typeof(IDiffItem))); /* PSEUDO CODE FOR THIS: * if (leftSomeLeft && leftCurrent.UniqueID == ID) * { * if (rightSomeLeft && rightCurrent.UniqueID == ID) * { * CheckConflicts(leftCurrent, rightCurrent) * rightSomeLeft = next(rightCurrent) * } * else * add(leftCurrent) * leftSomeLeft = next(leftCurrent) * } * else if (rightSomeLeft && rightCurrent.UniqueID == ID) * { * add(rightCurrent) * rightSomeLeft = next(rightCurrent) * } */ Expression leftShouldBeProcessed = Expression.AndAlso( leftSomeLeft, Expression.Equal( Expression.Property( Expression.Property( Expression.Convert( leftCurrent, typeof(IDiffClassItem) ), DiffItemsMembers.ClassProperty() ), FastPropertyMembers.UniqueID() ), Expression.Constant(property.UniqueID) ) ); Expression rightShouldBeProcessed = Expression.AndAlso( rightSomeLeft, Expression.Equal( Expression.Property( Expression.Property( Expression.Convert( rightCurrent, typeof(IDiffClassItem) ), DiffItemsMembers.ClassProperty() ), FastPropertyMembers.UniqueID() ), Expression.Constant(property.UniqueID) ) ); return(Expression.IfThenElse( leftShouldBeProcessed, Expression.Block( Expression.IfThenElse( rightShouldBeProcessed, Expression.Block( this.CompileCheckConflicts(property, leftCurrent, rightCurrent, conflicts, ret), this.MoveEnumerator(rightEnumerator, rightSomeLeft) ), Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), leftCurrent ) ), this.MoveEnumerator(leftEnumerator, leftSomeLeft) ), Expression.IfThen( rightShouldBeProcessed, Expression.Block( Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), rightCurrent ), this.MoveEnumerator(rightEnumerator, rightSomeLeft) ) ) )); }