public
sealed
class
ExpressionComparison : ExpressionVisitor
{
private
Expression
_comparand;
private
readonly
Queue
<
Expression
> _comparands;
public
ExpressionComparison(
Expression
firstExpression,
Expression
secondExpression)
{
ExpressionsAreEqual =
true
;
_comparands =
new
Queue
<
Expression
>(
new
ExpressionCollection(secondExpression));
Visit(firstExpression);
if
(0 < _comparands.Count)
ExpressionsAreEqual =
false
;
}
public
bool
ExpressionsAreEqual
{
get
;
private
set
; }
public
override
Expression
Visit(
Expression
node)
{
if
(
null
== node || !ExpressionsAreEqual)
return
node;
if
(0 == _comparands.Count)
return
Fail(node);
_comparand = _comparands.Peek();
if
(_comparand.NodeType != node.NodeType || _comparand.
Type
!= node.
Type
)
return
Fail(node);
_comparands.Dequeue();
return
base
.Visit(node);
}
protected
override
Expression
VisitBinary(BinaryExpression node)
{
BinaryExpression comparand = (BinaryExpression) _comparand;
if
(!AreEqual(node, comparand, x => x.Method))
return
Fail(node);
return
AreEqual(node, comparand, x => x.IsLifted, x => x.IsLiftedToNull)
?
base
.VisitBinary(node)
: Fail(node);
}
protected
override
Expression
VisitConstant(ConstantExpression node)
{
ConstantExpression comparand = (ConstantExpression)_comparand;
IEnumerable
nodeSequence = node.Value
as
IEnumerable
;
IEnumerable
comparandSequence = comparand.Value
as
IEnumerable
;
bool
areEqual =
null
!= nodeSequence &&
null
!= comparandSequence
? nodeSequence.SequenceEqual(comparandSequence)
: AreEqual(node, comparand, x => x.Value);
return
areEqual ?
base
.VisitConstant(node) : Fail(node);
}
protected
override
Expression
VisitDebugInfo(DebugInfoExpression node)
{
DebugInfoExpression comparand = (DebugInfoExpression) _comparand;
if
(!AreEqual(node, comparand, x => x.IsClear))
return
Fail(node);
return
AreEqual(node,
comparand,
x => x.EndColumn,
x => x.EndLine,
x => x.StartLine,
x => x.StartColumn)
?
base
.VisitDebugInfo(node)
: Fail(node);
}
protected
override
Expression
VisitDynamic(DynamicExpression node)
{
DynamicExpression comparand = (DynamicExpression) _comparand;
if
(!AreEqual(node, comparand, x => x.DelegateType))
return
Fail(node);
return
AreEqual(node, comparand, x => x.Binder)
?
base
.VisitDynamic(node)
: Fail(node);
}
protected
override
Expression
VisitGoto(GotoExpression node)
{
GotoExpression comparand = (GotoExpression) _comparand;
if
(!AreEqual(node, comparand, x => x.Kind))
return
Fail(node);
return
AreEqual(node.Target, comparand.Target)
?
base
.VisitGoto(node)
: Fail(node);
}
protected
override
Expression
VisitIndex(IndexExpression node)
{
IndexExpression comparand = (IndexExpression) _comparand;
return
AreEqual(node, comparand, x => x.Indexer)
?
base
.VisitIndex(node)
: Fail(node);
}
protected
override
Expression
VisitLabel(LabelExpression node)
{
LabelExpression comparand = (LabelExpression) _comparand;
return
AreEqual(comparand.Target, node.Target)
?
base
.VisitLabel(node)
: Fail(node);
}
protected
override
Expression
VisitLambda<T>(
Expression
<T> node)
{
LambdaExpression comparand = (LambdaExpression) _comparand;
if
(!AreEqual(node, comparand, x => x.Name))
return
Fail(node);
return
AreEqual(node, comparand, x => x.TailCall)
?
base
.VisitLambda(node)
: Fail(node);
}
protected
override
Expression
VisitListInit(ListInitExpression node)
{
ListInitExpression comparand = (ListInitExpression) _comparand;
return
AreEqual(node, comparand, x => x.Initializers, AreEqual)
?
base
.VisitListInit(node)
: Fail(node);
}
protected
override
Expression
VisitLoop(LoopExpression node)
{
LoopExpression comparand = (LoopExpression) _comparand;
if
(!AreEqual(comparand.BreakLabel, node.BreakLabel))
return
Fail(node);
return
AreEqual(comparand.ContinueLabel, node.ContinueLabel)
?
base
.VisitLoop(node)
: Fail(node);
}
protected
override
Expression
VisitMember(
MemberExpression
node)
{
MemberExpression
comparand = (
MemberExpression
) _comparand;
return
AreEqual(node, comparand, x => x.Member)
?
base
.VisitMember(node)
: Fail(node);
}
protected
override
Expression
VisitMemberInit(MemberInitExpression node)
{
MemberInitExpression comparand = (MemberInitExpression) _comparand;
return
AreEqual(node, comparand, x => x.Bindings, AreEqual)
?
base
.VisitMemberInit(node)
: Fail(node);
}
protected
override
Expression
VisitMethodCall(MethodCallExpression node)
{
MethodCallExpression comparand = (MethodCallExpression)_comparand;
return
AreEqual(node, comparand, x => x.Method)
?
base
.VisitMethodCall(node)
: Fail(node);
}
protected
override
Expression
VisitNew(NewExpression node)
{
NewExpression comparand = (NewExpression)_comparand;
if
(!AreEqual(node, comparand, x => x.Constructor))
return
Fail(node);
return
AreEqual(node, comparand, x => x.Members)
?
base
.VisitNew(node)
: Fail(node);
}
protected
override
Expression
VisitSwitch(SwitchExpression node)
{
SwitchExpression comparand = (SwitchExpression) _comparand;
return
AreEqual(node, comparand, x => x.Comparison)
?
base
.VisitSwitch(node)
: Fail(node);
}
protected
override
Expression
VisitTry(TryExpression node)
{
TryExpression comparand = (TryExpression) _comparand;
return
AreEqual(node, comparand, x => x.Handlers, AreEqual)
?
base
.VisitTry(node)
: Fail(node);
}
protected
override
Expression
VisitTypeBinary(TypeBinaryExpression node)
{
TypeBinaryExpression comparand = (TypeBinaryExpression) _comparand;
return
AreEqual(node, comparand, x => x.TypeOperand)
?
base
.VisitTypeBinary(node)
: Fail(node);
}
protected
override
Expression
VisitUnary(UnaryExpression node)
{
UnaryExpression comparand = (UnaryExpression)_comparand;
if
(!AreEqual(node, comparand, x => x.Method))
return
Fail(node);
return
AreEqual(node, comparand, x => x.IsLifted, x => x.IsLiftedToNull)
?
base
.VisitUnary(node)
: Fail(node);
}
private
static
bool
AreEqual(LabelTarget first, LabelTarget second)
{
if
(
null
== first ||
null
== second)
{
return
first == second;
}
return
first.Name == second.Name && first.
Type
== second.
Type
;
}
private
static
bool
AreEqual(CatchBlock first, CatchBlock second)
{
return
first.Test == second.Test;
}
private
static
bool
AreEqual(ElementInit first, ElementInit second)
{
return
first.AddMethod == second.AddMethod;
}
private
static
bool
AreEqual(MemberBinding first, MemberBinding second)
{
if
(first.BindingType != second.BindingType || first.Member != second.Member)
return
false
;
if
(MemberBindingType.ListBinding != first.BindingType)
return
true
;
MemberListBinding firstList = (MemberListBinding)first;
MemberListBinding secondList = (MemberListBinding)second;
return
AreEqual(firstList, secondList, x => x.Initializers, AreEqual);
}
private
static
bool
AreEqual<T,TMember>(T first, T second,
params
Func
<T,TMember>[] reader)
{
return
reader.All(r => EqualityComparer<TMember>.Default.Equals(r(first), r(second)));
}
private
static
bool
AreEqual<T, TMember>(
T first,
T second,
Func
<T, ReadOnlyCollection<TMember>> reader,
Func
<TMember, TMember,
bool
> comparer =
null
)
{
if
(
null
== comparer)
comparer = (x, y) => EqualityComparer<TMember>.Default.Equals(x, y);
ReadOnlyCollection<TMember> firstCollection = reader(first);
ReadOnlyCollection<TMember> secondCollection = reader(second);
if
(
null
== firstCollection ||
null
== secondCollection)
{
return
firstCollection == secondCollection;
}
return
!firstCollection.Where((t, i) => !comparer(t, secondCollection[i])).Any();
}
private
Expression
Fail(
Expression
node)
{
ExpressionsAreEqual =
false
;
return
node;
}
}