18
18
using System . Collections . ObjectModel ;
19
19
using System . Linq ;
20
20
using System . Linq . Expressions ;
21
+ using System . Runtime . CompilerServices ;
21
22
using System . Text ;
22
23
using System . Text . RegularExpressions ;
23
24
@@ -132,7 +133,7 @@ protected override Expression VisitConstant(ConstantExpression node)
132
133
// need to check node.Type instead of value.GetType() because boxed Nullable<T> values are boxed as <T>
133
134
if ( node . Type . IsGenericType && node . Type . GetGenericTypeDefinition ( ) == typeof ( Nullable < > ) )
134
135
{
135
- _sb . AppendFormat ( "({0})" , FriendlyClassName ( node . Type ) ) ;
136
+ _sb . AppendFormat ( "({0})" , FriendlyTypeName ( node . Type ) ) ;
136
137
}
137
138
VisitValue ( node . Value ) ;
138
139
return node ;
@@ -179,7 +180,7 @@ protected override Expression VisitInvocation(InvocationExpression node)
179
180
protected override Expression VisitLambda ( LambdaExpression node )
180
181
{
181
182
_sb . Append ( "(" ) ;
182
- _sb . Append ( string . Join ( ", " , node . Parameters . Select ( p => p . Type . Name + " " + p . Name ) . ToArray ( ) ) ) ;
183
+ _sb . Append ( string . Join ( ", " , node . Parameters . Select ( p => FriendlyTypeName ( p . Type ) + " " + p . Name ) . ToArray ( ) ) ) ;
183
184
_sb . Append ( ") => " ) ;
184
185
Visit ( node . Body ) ;
185
186
return node ;
@@ -284,7 +285,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
284
285
{
285
286
if ( node . Method . IsStatic )
286
287
{
287
- _sb . Append ( node . Method . DeclaringType . Name ) ;
288
+ _sb . Append ( FriendlyTypeName ( node . Method . DeclaringType ) ) ;
288
289
}
289
290
else
290
291
{
@@ -294,7 +295,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
294
295
_sb . Append ( node . Method . Name ) ;
295
296
if ( node . Method . IsGenericMethod )
296
297
{
297
- _sb . AppendFormat ( "<{0}>" , string . Join ( ", " , node . Method . GetGenericArguments ( ) . Select ( t => FriendlyClassName ( t ) ) . ToArray ( ) ) ) ;
298
+ _sb . AppendFormat ( "<{0}>" , string . Join ( ", " , node . Method . GetGenericArguments ( ) . Select ( t => FriendlyTypeName ( t ) ) . ToArray ( ) ) ) ;
298
299
}
299
300
_sb . Append ( "(" ) ;
300
301
var separator = "" ;
@@ -316,7 +317,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
316
317
protected override NewExpression VisitNew ( NewExpression node )
317
318
{
318
319
_sb . Append ( "new " ) ;
319
- _sb . Append ( node . Type . Name ) ;
320
+ _sb . Append ( FriendlyTypeName ( node . Type ) ) ;
320
321
_sb . Append ( "(" ) ;
321
322
var separator = "" ;
322
323
foreach ( var arg in node . Arguments )
@@ -337,7 +338,7 @@ protected override NewExpression VisitNew(NewExpression node)
337
338
protected override Expression VisitNewArray ( NewArrayExpression node )
338
339
{
339
340
var elementType = node . Type . GetElementType ( ) ;
340
- _sb . AppendFormat ( "new {0}[] {{ " , PublicClassName ( elementType ) ) ;
341
+ _sb . AppendFormat ( "new {0}[] {{ " , FriendlyTypeName ( elementType ) ) ;
341
342
var separator = "" ;
342
343
foreach ( var item in node . Expressions )
343
344
{
@@ -370,7 +371,7 @@ protected override Expression VisitTypeBinary(TypeBinaryExpression node)
370
371
_sb . Append ( "(" ) ;
371
372
Visit ( node . Expression ) ;
372
373
_sb . Append ( " is " ) ;
373
- _sb . Append ( FriendlyClassName ( node . TypeOperand ) ) ;
374
+ _sb . Append ( FriendlyTypeName ( node . TypeOperand ) ) ;
374
375
_sb . Append ( ")" ) ;
375
376
return node ;
376
377
}
@@ -385,7 +386,7 @@ protected override Expression VisitUnary(UnaryExpression node)
385
386
switch ( node . NodeType )
386
387
{
387
388
case ExpressionType . ArrayLength : break ;
388
- case ExpressionType . Convert : _sb . AppendFormat ( "({0})" , FriendlyClassName ( node . Type ) ) ; break ;
389
+ case ExpressionType . Convert : _sb . AppendFormat ( "({0})" , FriendlyTypeName ( node . Type ) ) ; break ;
389
390
case ExpressionType . Negate : _sb . Append ( "-" ) ; break ;
390
391
case ExpressionType . Not : _sb . Append ( "!" ) ; break ;
391
392
case ExpressionType . Quote : break ;
@@ -401,31 +402,35 @@ protected override Expression VisitUnary(UnaryExpression node)
401
402
}
402
403
403
404
// private methods
404
- private string FriendlyClassName ( Type type )
405
+ private string FriendlyTypeName ( Type type )
405
406
{
406
- if ( ! type . IsGenericType )
407
+ var typeName = IsAnonymousType ( type ) ? "__AnonymousType" : type . Name ;
408
+
409
+ if ( type . IsGenericType )
407
410
{
408
- return type . Name ;
411
+ var sb = new StringBuilder ( ) ;
412
+ sb . AppendFormat ( "{0}<" , Regex . Replace ( typeName , @"\`\d+$" , "" ) ) ;
413
+ foreach ( var typeParameter in type . GetGenericArguments ( ) )
414
+ {
415
+ sb . AppendFormat ( "{0}, " , FriendlyTypeName ( typeParameter ) ) ;
416
+ }
417
+ sb . Remove ( sb . Length - 2 , 2 ) ;
418
+ sb . Append ( ">" ) ;
419
+ return sb . ToString ( ) ;
409
420
}
410
-
411
- var sb = new StringBuilder ( ) ;
412
- sb . AppendFormat ( "{0}<" , Regex . Replace ( type . Name , @"\`\d+$" , "" ) ) ;
413
- foreach ( var typeParameter in type . GetGenericArguments ( ) )
421
+ else
414
422
{
415
- sb . AppendFormat ( "{0}, " , FriendlyClassName ( typeParameter ) ) ;
423
+ return typeName ;
416
424
}
417
- sb . Remove ( sb . Length - 2 , 2 ) ;
418
- sb . Append ( ">" ) ;
419
- return sb . ToString ( ) ;
420
425
}
421
426
422
- private string PublicClassName ( Type type )
427
+ private bool IsAnonymousType ( Type type )
423
428
{
424
- while ( ! type . IsPublic )
425
- {
426
- type = type . BaseType ;
427
- }
428
- return FriendlyClassName ( type ) ;
429
+ // don't test for too many things in case implementation details change in the future
430
+ return
431
+ Attribute . IsDefined ( type , typeof ( CompilerGeneratedAttribute ) , false ) &&
432
+ type . IsGenericType &&
433
+ type . Name . Contains ( "Anon" ) ; // don't check for more than "Anon" so it works in mono also
429
434
}
430
435
431
436
private void VisitValue ( object value )
@@ -440,7 +445,7 @@ private void VisitValue(object value)
440
445
if ( a != null && a . Rank == 1 )
441
446
{
442
447
var elementType = a . GetType ( ) . GetElementType ( ) ;
443
- _sb . AppendFormat ( "{0}[]:{{" , elementType . Name ) ;
448
+ _sb . AppendFormat ( "{0}[]:{{" , FriendlyTypeName ( elementType ) ) ;
444
449
var separator = " " ;
445
450
foreach ( var item in a )
446
451
{
@@ -487,7 +492,7 @@ private void VisitValue(object value)
487
492
var e = value as Enum ;
488
493
if ( e != null )
489
494
{
490
- _sb . Append ( e . GetType ( ) . Name + "." + e . ToString ( ) ) ;
495
+ _sb . Append ( FriendlyTypeName ( e . GetType ( ) ) + "." + e . ToString ( ) ) ;
491
496
return ;
492
497
}
493
498
@@ -527,7 +532,7 @@ private void VisitValue(object value)
527
532
var type = value as Type ;
528
533
if ( type != null )
529
534
{
530
- _sb . AppendFormat ( "typeof({0})" , FriendlyClassName ( type ) ) ;
535
+ _sb . AppendFormat ( "typeof({0})" , FriendlyTypeName ( type ) ) ;
531
536
return ;
532
537
}
533
538
0 commit comments