1818using System . Collections . ObjectModel ;
1919using System . Linq ;
2020using System . Linq . Expressions ;
21+ using System . Runtime . CompilerServices ;
2122using System . Text ;
2223using System . Text . RegularExpressions ;
2324
@@ -132,7 +133,7 @@ protected override Expression VisitConstant(ConstantExpression node)
132133 // need to check node.Type instead of value.GetType() because boxed Nullable<T> values are boxed as <T>
133134 if ( node . Type . IsGenericType && node . Type . GetGenericTypeDefinition ( ) == typeof ( Nullable < > ) )
134135 {
135- _sb . AppendFormat ( "({0})" , FriendlyClassName ( node . Type ) ) ;
136+ _sb . AppendFormat ( "({0})" , FriendlyTypeName ( node . Type ) ) ;
136137 }
137138 VisitValue ( node . Value ) ;
138139 return node ;
@@ -179,7 +180,7 @@ protected override Expression VisitInvocation(InvocationExpression node)
179180 protected override Expression VisitLambda ( LambdaExpression node )
180181 {
181182 _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 ( ) ) ) ;
183184 _sb . Append ( ") => " ) ;
184185 Visit ( node . Body ) ;
185186 return node ;
@@ -284,7 +285,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
284285 {
285286 if ( node . Method . IsStatic )
286287 {
287- _sb . Append ( node . Method . DeclaringType . Name ) ;
288+ _sb . Append ( FriendlyTypeName ( node . Method . DeclaringType ) ) ;
288289 }
289290 else
290291 {
@@ -294,7 +295,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
294295 _sb . Append ( node . Method . Name ) ;
295296 if ( node . Method . IsGenericMethod )
296297 {
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 ( ) ) ) ;
298299 }
299300 _sb . Append ( "(" ) ;
300301 var separator = "" ;
@@ -316,7 +317,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
316317 protected override NewExpression VisitNew ( NewExpression node )
317318 {
318319 _sb . Append ( "new " ) ;
319- _sb . Append ( node . Type . Name ) ;
320+ _sb . Append ( FriendlyTypeName ( node . Type ) ) ;
320321 _sb . Append ( "(" ) ;
321322 var separator = "" ;
322323 foreach ( var arg in node . Arguments )
@@ -337,7 +338,7 @@ protected override NewExpression VisitNew(NewExpression node)
337338 protected override Expression VisitNewArray ( NewArrayExpression node )
338339 {
339340 var elementType = node . Type . GetElementType ( ) ;
340- _sb . AppendFormat ( "new {0}[] {{ " , PublicClassName ( elementType ) ) ;
341+ _sb . AppendFormat ( "new {0}[] {{ " , FriendlyTypeName ( elementType ) ) ;
341342 var separator = "" ;
342343 foreach ( var item in node . Expressions )
343344 {
@@ -370,7 +371,7 @@ protected override Expression VisitTypeBinary(TypeBinaryExpression node)
370371 _sb . Append ( "(" ) ;
371372 Visit ( node . Expression ) ;
372373 _sb . Append ( " is " ) ;
373- _sb . Append ( FriendlyClassName ( node . TypeOperand ) ) ;
374+ _sb . Append ( FriendlyTypeName ( node . TypeOperand ) ) ;
374375 _sb . Append ( ")" ) ;
375376 return node ;
376377 }
@@ -385,7 +386,7 @@ protected override Expression VisitUnary(UnaryExpression node)
385386 switch ( node . NodeType )
386387 {
387388 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 ;
389390 case ExpressionType . Negate : _sb . Append ( "-" ) ; break ;
390391 case ExpressionType . Not : _sb . Append ( "!" ) ; break ;
391392 case ExpressionType . Quote : break ;
@@ -401,31 +402,35 @@ protected override Expression VisitUnary(UnaryExpression node)
401402 }
402403
403404 // private methods
404- private string FriendlyClassName ( Type type )
405+ private string FriendlyTypeName ( Type type )
405406 {
406- if ( ! type . IsGenericType )
407+ var typeName = IsAnonymousType ( type ) ? "__AnonymousType" : type . Name ;
408+
409+ if ( type . IsGenericType )
407410 {
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 ( ) ;
409420 }
410-
411- var sb = new StringBuilder ( ) ;
412- sb . AppendFormat ( "{0}<" , Regex . Replace ( type . Name , @"\`\d+$" , "" ) ) ;
413- foreach ( var typeParameter in type . GetGenericArguments ( ) )
421+ else
414422 {
415- sb . AppendFormat ( "{0}, " , FriendlyClassName ( typeParameter ) ) ;
423+ return typeName ;
416424 }
417- sb . Remove ( sb . Length - 2 , 2 ) ;
418- sb . Append ( ">" ) ;
419- return sb . ToString ( ) ;
420425 }
421426
422- private string PublicClassName ( Type type )
427+ private bool IsAnonymousType ( Type type )
423428 {
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
429434 }
430435
431436 private void VisitValue ( object value )
@@ -440,7 +445,7 @@ private void VisitValue(object value)
440445 if ( a != null && a . Rank == 1 )
441446 {
442447 var elementType = a . GetType ( ) . GetElementType ( ) ;
443- _sb . AppendFormat ( "{0}[]:{{" , elementType . Name ) ;
448+ _sb . AppendFormat ( "{0}[]:{{" , FriendlyTypeName ( elementType ) ) ;
444449 var separator = " " ;
445450 foreach ( var item in a )
446451 {
@@ -487,7 +492,7 @@ private void VisitValue(object value)
487492 var e = value as Enum ;
488493 if ( e != null )
489494 {
490- _sb . Append ( e . GetType ( ) . Name + "." + e . ToString ( ) ) ;
495+ _sb . Append ( FriendlyTypeName ( e . GetType ( ) ) + "." + e . ToString ( ) ) ;
491496 return ;
492497 }
493498
@@ -527,7 +532,7 @@ private void VisitValue(object value)
527532 var type = value as Type ;
528533 if ( type != null )
529534 {
530- _sb . AppendFormat ( "typeof({0})" , FriendlyClassName ( type ) ) ;
535+ _sb . AppendFormat ( "typeof({0})" , FriendlyTypeName ( type ) ) ;
531536 return ;
532537 }
533538
0 commit comments