private MethodCallExpression NewDiffReplaced(ParameterExpression ret, Property property, ParameterExpression @base, ParameterExpression changed) { MemberExpression baseProperty = Expression.Property(@base, property.ReflectionPropertyInfo); MemberExpression changedProperty = Expression.Property(changed, property.ReflectionPropertyInfo); return(Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), Expression.New( DiffItemsMembers.NewClassReplaced(property.Type), Expression.Constant(property), baseProperty, changedProperty ) )); }
private Expression NewDiffChanged(ParameterExpression ret, Property property, ParameterExpression @base, ParameterExpression changed) { IDiffAlgorithm diff = this.aMergerImplementation.Partial.Algorithms.GetDiffAlgorithm(property.Type); if (diff.IsDirect) { return(this.NewDiffReplaced(ret, property, @base, changed)); } MemberExpression baseProperty = Expression.Property(@base, property.ReflectionPropertyInfo); MemberExpression changedProperty = Expression.Property(changed, property.ReflectionPropertyInfo); ParameterExpression tmp = Expression.Parameter(typeof(IDiff <>).MakeGenericType(property.Type), "tmp"); return(Expression.Block( new[] { tmp }, Expression.Assign( tmp, Expression.Call( Expression.Constant(diff), DiffAlgorithmMembers.Compute(property.Type), baseProperty, changedProperty ) ), Expression.IfThenElse( Expression.NotEqual( Expression.Property(tmp, DiffMembers.Count()), Expression.Constant(0) ), Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), Expression.New( DiffItemsMembers.NewClassChanged(property.Type), Expression.Constant(property), tmp ) ), this.NewDiffUnchanged(ret, property, @base) ) )); }
private Expression NewDiffUnchanged(ParameterExpression ret, Property property, ParameterExpression value) { if (!this.aAlwaysIncludedProperties.Contains(property)) { return(Expression.Empty()); } MemberExpression valueProperty = Expression.Property(value, property.ReflectionPropertyInfo); return(Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), Expression.New( DiffItemsMembers.NewClassUnchanged(property.Type), Expression.Constant(property), valueProperty ) )); }
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) ) ) )); }
private Expression CompileCheckConflicts(Property property, Expression leftCurrent, Expression rightCurrent, Expression conflicts, Expression ret) { /* PSEUDO CODE FOR THIS: * if (leftCurrent is Unchanged) * { * add(rightCurrent) * } * else if (rightCurrent is Unchanged) * { * add(leftCurrent) * } * else if (leftCurrent is Replace || rightCurrent is Replace) * { * if (leftCurrent == rightCurrent) * add(leftCurrent) * else * { * conflict = Conflict(leftCurrent, rightCurrent) * add(conflict) * conflicts.register(conflict) * } * } * else if (leftCurrent is Changed && rightCurrent is Changed) * { * add(algorithm.Merge(leftCurrent.ValueDiff, rightCurrent.ValueDiff, conflicts)) * } * else * throw */ IMergeDiffsAlgorithm algorithm = this.aMergerImplementation.Partial.Algorithms.GetMergeDiffsAlgorithm(property.Type); Type itemReplacedType = typeof(IDiffItemReplaced <>).MakeGenericType(property.Type); ParameterExpression conflict = Expression.Parameter(typeof(IDiffItemConflicted), "conflict"); return(Expression.IfThenElse( Expression.TypeIs(leftCurrent, typeof(IDiffItemUnchanged)), Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), rightCurrent ), Expression.IfThenElse( Expression.TypeIs(rightCurrent, typeof(IDiffItemUnchanged)), Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), leftCurrent ), Expression.IfThenElse( Expression.OrElse( Expression.TypeIs(leftCurrent, itemReplacedType), Expression.TypeIs(rightCurrent, itemReplacedType) ), Expression.IfThenElse( Expression.Call( null, ObjectMembers.Equals(), leftCurrent, rightCurrent ), Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), leftCurrent ), Expression.Block( new[] { conflict }, Expression.Assign( conflict, Expression.New( DiffItemsMembers.NewConflict(), leftCurrent, rightCurrent ) ), Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), conflict ), Expression.Call( conflicts, ConflictContainerMembers.RegisterConflict(), conflict ) ) ), Expression.IfThenElse( Expression.AndAlso( Expression.TypeIs(leftCurrent, typeof(IDiffItemChanged)), Expression.TypeIs(rightCurrent, typeof(IDiffItemChanged)) ), Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), Expression.New( DiffItemsMembers.NewClassChanged(property.Type), Expression.Constant(property), Expression.Call( Expression.Constant(algorithm, typeof(IMergeDiffsAlgorithm <>).MakeGenericType(property.Type)), MergeDiffsAlgorithmMembers.MergeDiffs(property.Type), Expression.Property( Expression.Convert(leftCurrent, typeof(IDiffItemChanged <>).MakeGenericType(property.Type)), DiffItemsMembers.ChangedDiff(property.Type) ), Expression.Property( Expression.Convert(rightCurrent, typeof(IDiffItemChanged <>).MakeGenericType(property.Type)), DiffItemsMembers.ChangedDiff(property.Type) ), conflicts ) ) ), Expression.Throw( Expression.New(typeof(Exception)) ) ) ) ) )); }
private Func <TType, TType, List <IDiffItem> > CompileDiff() { ParameterExpression ret = Expression.Parameter(typeof(List <IDiffItem>), "ret"); ParameterExpression @base = Expression.Parameter(typeof(TType), "base"); ParameterExpression changed = Expression.Parameter(typeof(TType), "changed"); Expression differ; if (this.aIDProperty == null) { differ = Expression.IfThen( ExpressionExtensions.NotEqual(@base, changed), Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), Expression.New( DiffItemsMembers.NewValueReplaced(typeof(TType)), @base, changed ) ) ); } else { differ = Expression.IfThen( ExpressionExtensions.NotEqual( Expression.Property(@base, this.aIDProperty.ReflectionPropertyInfo), Expression.Property(changed, this.aIDProperty.ReflectionPropertyInfo) ), Expression.Call( ret, ListMembers.Add(typeof(IDiffItem)), Expression.New( DiffItemsMembers.NewValueReplaced(typeof(TType)), @base, changed ) ) ); } if (!typeof(TType).IsValueType) { differ = Expression.IfThenElse( Expression.OrElse( Expression.ReferenceEqual(@base, Expression.Constant(null)), Expression.ReferenceEqual(changed, Expression.Constant(null)) ), Expression.IfThen( Expression.ReferenceEqual(@base, changed), Expression.New( DiffItemsMembers.NewValueReplaced(typeof(TType)), @base, changed ) ), differ ); } Expression <Func <TType, TType, List <IDiffItem> > > comparer = Expression.Lambda <Func <TType, TType, List <IDiffItem> > >( Expression.Block( new[] { ret }, Expression.Assign( ret, Expression.New( ListMembers.NewWithCount(typeof(IDiffItem)), Expression.Constant(1) // maximum number of changes ) ), differ, ret ), @base, changed ); return(comparer.Compile()); }