@@ -93,17 +93,40 @@ private static string Hash(string input)
9393
9494 private sealed class CanonicalExpressionPrinter ( StringBuilder sb ) : ExpressionVisitor
9595 {
96+ public override Expression Visit ( Expression node )
97+ {
98+ if ( node == null )
99+ {
100+ sb . Append ( "NULL" ) ;
101+ return null ;
102+ }
103+
104+ sb . Append ( "NODE(" ) ;
105+ sb . Append ( node . NodeType ) ;
106+ sb . Append ( ":" ) ;
107+ AppendType ( node . Type ) ;
108+ sb . Append ( ")" ) ;
109+
110+ return base . Visit ( node ) ;
111+ }
112+
96113 protected override Expression VisitConstant ( ConstantExpression node )
97114 {
98115 // Remove closure object identity
99116 if ( node . Type . Name . Contains ( "DisplayClass" ) )
100117 {
101- sb . Append ( $ "CONST(closure:{ node . Type . FullName } )") ;
118+ sb . Append ( "CONST(closure:" ) ;
119+ AppendType ( node . Type ) ;
120+ sb . Append ( ")" ) ;
102121 return node ;
103122 }
104123
105124 // Normal constants
106- sb . Append ( $ "CONST({ node . Value } )") ;
125+ sb . Append ( "CONST(" ) ;
126+ sb . Append ( node . Value ) ;
127+ sb . Append ( ":" ) ;
128+ AppendType ( node . Type ) ;
129+ sb . Append ( ")" ) ;
107130 return node ;
108131 }
109132
@@ -114,38 +137,136 @@ protected override Expression VisitMember(MemberExpression node)
114137 {
115138 // Include the closure declaring type + member type to handle array/ref struct differences
116139 sb . Append ( "CLOSURE_MEMBER(" ) ;
117- sb . Append ( c . Type . FullName ) ;
140+ AppendType ( c . Type ) ;
118141 sb . Append ( "." ) ;
119142 sb . Append ( node . Member . Name ) ;
120143 sb . Append ( ":" ) ;
121- sb . Append ( node . Type . FullName ) ;
144+ AppendType ( node . Type ) ;
122145 sb . Append ( ")" ) ;
123146 return node ;
124147 }
125- sb . Append ( $ "MEMBER({ node . Member . DeclaringType } .{ node . Member . Name } :{ node . Type . FullName } )") ;
148+ sb . Append ( "MEMBER(" ) ;
149+ AppendType ( node . Member . DeclaringType ) ;
150+ sb . Append ( "." ) ;
151+ sb . Append ( node . Member . Name ) ;
152+ sb . Append ( ":" ) ;
153+ AppendType ( node . Type ) ;
154+ sb . Append ( ")" ) ;
126155 return base . VisitMember ( node ) ;
127156 }
128157
129158 protected override Expression VisitLambda < T > ( Expression < T > node )
130159 {
131160 sb . Append ( "LAMBDA(" ) ;
132161 foreach ( var p in node . Parameters )
133- sb . Append ( p . Type . FullName + ";" ) ;
162+ {
163+ AppendType ( p . Type ) ;
164+ sb . Append ( ";" ) ;
165+ }
166+ sb . Append ( "):" ) ;
167+ AppendType ( node . ReturnType ) ;
134168 sb . Append ( ")=>" ) ;
135169 return base . VisitLambda ( node ) ;
136170 }
137171
138172 protected override Expression VisitBinary ( BinaryExpression node )
139173 {
140- sb . Append ( $ "BIN({ node . NodeType } )") ;
174+ sb . Append ( "BIN(" ) ;
175+ sb . Append ( node . NodeType ) ;
176+ sb . Append ( ":" ) ;
177+ AppendType ( node . Type ) ;
178+ if ( node . Method != null )
179+ {
180+ sb . Append ( ":" ) ;
181+ AppendMethod ( node . Method ) ;
182+ }
183+ sb . Append ( ")" ) ;
141184 return base . VisitBinary ( node ) ;
142185 }
143186
144187 protected override Expression VisitParameter ( ParameterExpression node )
145188 {
146- sb . Append ( $ "PARAM({ node . Type . FullName } )") ;
189+ sb . Append ( "PARAM(" ) ;
190+ AppendType ( node . Type ) ;
191+ sb . Append ( ")" ) ;
147192 return node ;
148193 }
194+
195+ protected override Expression VisitMethodCall ( MethodCallExpression node )
196+ {
197+ sb . Append ( "CALL(" ) ;
198+ AppendMethod ( node . Method ) ;
199+ sb . Append ( ":" ) ;
200+ AppendType ( node . Type ) ;
201+ sb . Append ( ")" ) ;
202+ return base . VisitMethodCall ( node ) ;
203+ }
204+
205+ protected override Expression VisitNew ( NewExpression node )
206+ {
207+ sb . Append ( "NEW(" ) ;
208+ AppendType ( node . Type ) ;
209+ if ( node . Constructor != null )
210+ {
211+ sb . Append ( ":" ) ;
212+ AppendConstructor ( node . Constructor ) ;
213+ }
214+ sb . Append ( ")" ) ;
215+ return base . VisitNew ( node ) ;
216+ }
217+
218+ protected override Expression VisitUnary ( UnaryExpression node )
219+ {
220+ sb . Append ( "UNARY(" ) ;
221+ sb . Append ( node . NodeType ) ;
222+ sb . Append ( ":" ) ;
223+ AppendType ( node . Type ) ;
224+ if ( node . Method != null )
225+ {
226+ sb . Append ( ":" ) ;
227+ AppendMethod ( node . Method ) ;
228+ }
229+ sb . Append ( ")" ) ;
230+ return base . VisitUnary ( node ) ;
231+ }
232+
233+ private void AppendConstructor ( ConstructorInfo constructor )
234+ {
235+ AppendType ( constructor . DeclaringType ) ;
236+ sb . Append ( "(" ) ;
237+ var parameters = constructor . GetParameters ( ) ;
238+ for ( int i = 0 ; i < parameters . Length ; i ++ )
239+ {
240+ if ( i > 0 )
241+ sb . Append ( "," ) ;
242+
243+ AppendType ( parameters [ i ] . ParameterType ) ;
244+ }
245+ sb . Append ( ")" ) ;
246+ }
247+
248+ private void AppendMethod ( MethodInfo method )
249+ {
250+ AppendType ( method . DeclaringType ) ;
251+ sb . Append ( "." ) ;
252+ sb . Append ( method . Name ) ;
253+ sb . Append ( "(" ) ;
254+ var parameters = method . GetParameters ( ) ;
255+ for ( int i = 0 ; i < parameters . Length ; i ++ )
256+ {
257+ if ( i > 0 )
258+ sb . Append ( "," ) ;
259+
260+ AppendType ( parameters [ i ] . ParameterType ) ;
261+ }
262+ sb . Append ( "):" ) ;
263+ AppendType ( method . ReturnType ) ;
264+ }
265+
266+ private void AppendType ( Type type )
267+ {
268+ sb . Append ( type ? . ToString ( ) ?? "<null>" ) ;
269+ }
149270 }
150271
151272 private sealed class CacheableExpressionVisitor : ExpressionVisitor
0 commit comments