1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
namespace System.Web.Mvc.ExpressionUtil {
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
// This is a visitor which produces a fingerprint of an expression. It doesn't
// rewrite the expression in a form which can be compiled and cached.
internal sealed class FingerprintingExpressionVisitor : ExpressionVisitor {
private readonly List<object> _seenConstants = new List<object>();
private readonly List<ParameterExpression> _seenParameters = new List<ParameterExpression>();
private readonly ExpressionFingerprintChain _currentChain = new ExpressionFingerprintChain();
private bool _gaveUp;
private FingerprintingExpressionVisitor() { }
private T GiveUp<T>(T node) {
// We don't understand this node, so just quit.
_gaveUp = true;
return node;
}
// Returns the fingerprint chain + captured constants list for this expression, or null
// if the expression couldn't be fingerprinted.
public static ExpressionFingerprintChain GetFingerprintChain(Expression expr, out List<object> capturedConstants) {
FingerprintingExpressionVisitor visitor = new FingerprintingExpressionVisitor();
visitor.Visit(expr);
if (visitor._gaveUp) {
capturedConstants = null;
return null;
}
else {
capturedConstants = visitor._seenConstants;
return visitor._currentChain;
}
}
public override Expression Visit(Expression node) {
if (node == null) {
_currentChain.Elements.Add(null);
return null;
}
else {
return base.Visit(node);
}
}
protected override Expression VisitBinary(BinaryExpression node) {
if (_gaveUp) { return node; }
_currentChain.Elements.Add(new BinaryExpressionFingerprint(node.NodeType, node.Type, node.Method));
return base.VisitBinary(node);
}
protected override Expression VisitBlock(BlockExpression node) {
return GiveUp(node);
}
protected override CatchBlock VisitCatchBlock(CatchBlock node) {
return GiveUp(node);
}
protected override Expression VisitConditional(ConditionalExpression node) {
if (_gaveUp) { return node; }
_currentChain.Elements.Add(new ConditionalExpressionFingerprint(node.NodeType, node.Type));
return base.VisitConditional(node);
}
protected override Expression VisitConstant(ConstantExpression node) {
if (_gaveUp) { return node; }
_seenConstants.Add(node.Value);
_currentChain.Elements.Add(new ConstantExpressionFingerprint(node.NodeType, node.Type));
return base.VisitConstant(node);
}
protected override Expression VisitDebugInfo(DebugInfoExpression node) {
return GiveUp(node);
}
protected override Expression VisitDefault(DefaultExpression node) {
if (_gaveUp) { return node; }
_currentChain.Elements.Add(new DefaultExpressionFingerprint(node.NodeType, node.Type));
return base.VisitDefault(node);
}
protected override Expression VisitDynamic(DynamicExpression node) {
return GiveUp(node);
}
protected override ElementInit VisitElementInit(ElementInit node) {
return GiveUp(node);
}
protected override Expression VisitExtension(Expression node) {
return GiveUp(node);
}
protected override Expression VisitGoto(GotoExpression node) {
return GiveUp(node);
}
protected override Expression VisitIndex(IndexExpression node) {
if (_gaveUp) { return node; }
_currentChain.Elements.Add(new IndexExpressionFingerprint(node.NodeType, node.Type, node.Indexer));
return base.VisitIndex(node);
}
protected override Expression VisitInvocation(InvocationExpression node) {
return GiveUp(node);
}
protected override Expression VisitLabel(LabelExpression node) {
return GiveUp(node);
}
protected override LabelTarget VisitLabelTarget(LabelTarget node) {
return GiveUp(node);
}
protected override Expression VisitLambda<T>(Expression<T> node) {
if (_gaveUp) { return node; }
_currentChain.Elements.Add(new LambdaExpressionFingerprint(node.NodeType, node.Type));
return base.VisitLambda<T>(node);
}
protected override Expression VisitListInit(ListInitExpression node) {
return GiveUp(node);
}
protected override Expression VisitLoop(LoopExpression node) {
return GiveUp(node);
}
protected override Expression VisitMember(MemberExpression node) {
if (_gaveUp) { return node; }
_currentChain.Elements.Add(new MemberExpressionFingerprint(node.NodeType, node.Type, node.Member));
return base.VisitMember(node);
}
protected override MemberAssignment VisitMemberAssignment(MemberAssignment node) {
return GiveUp(node);
}
protected override MemberBinding VisitMemberBinding(MemberBinding node) {
return GiveUp(node);
}
protected override Expression VisitMemberInit(MemberInitExpression node) {
return GiveUp(node);
}
protected override MemberListBinding VisitMemberListBinding(MemberListBinding node) {
return GiveUp(node);
}
protected override MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding node) {
return GiveUp(node);
}
protected override Expression VisitMethodCall(MethodCallExpression node) {
if (_gaveUp) { return node; }
_currentChain.Elements.Add(new MethodCallExpressionFingerprint(node.NodeType, node.Type, node.Method));
return base.VisitMethodCall(node);
}
protected override Expression VisitNew(NewExpression node) {
return GiveUp(node);
}
protected override Expression VisitNewArray(NewArrayExpression node) {
return GiveUp(node);
}
protected override Expression VisitParameter(ParameterExpression node) {
if (_gaveUp) { return node; }
int parameterIndex = _seenParameters.IndexOf(node);
if (parameterIndex < 0) {
// first time seeing this parameter
parameterIndex = _seenParameters.Count;
_seenParameters.Add(node);
}
_currentChain.Elements.Add(new ParameterExpressionFingerprint(node.NodeType, node.Type, parameterIndex));
return base.VisitParameter(node);
}
protected override Expression VisitRuntimeVariables(RuntimeVariablesExpression node) {
return GiveUp(node);
}
protected override Expression VisitSwitch(SwitchExpression node) {
return GiveUp(node);
}
protected override SwitchCase VisitSwitchCase(SwitchCase node) {
return GiveUp(node);
}
protected override Expression VisitTry(TryExpression node) {
return GiveUp(node);
}
protected override Expression VisitTypeBinary(TypeBinaryExpression node) {
if (_gaveUp) { return node; }
_currentChain.Elements.Add(new TypeBinaryExpressionFingerprint(node.NodeType, node.Type, node.TypeOperand));
return base.VisitTypeBinary(node);
}
protected override Expression VisitUnary(UnaryExpression node) {
if (_gaveUp) { return node; }
_currentChain.Elements.Add(new UnaryExpressionFingerprint(node.NodeType, node.Type, node.Method));
return base.VisitUnary(node);
}
}
}
|