@@ -1488,69 +1488,155 @@ internal static StringBuilder AppendName<T>(this StringBuilder sb, string name,
1488
1488
: sb . Append ( type . ToCode ( true , null ) ) . Append ( '_' ) . Append ( identity . GetHashCode ( ) ) ;
1489
1489
1490
1490
/// <summary>Converts the <paramref name="type"/> into the proper C# representation.</summary>
1491
- public static string ToCode ( this Type type , bool stripNamespace = false , Func < Type , string , string > printType = null )
1491
+ public static string ToCode ( this Type type ,
1492
+ bool stripNamespace = false , Func < Type , string , string > printType = null , bool printGenericTypeArgs = false )
1492
1493
{
1494
+ if ( type . IsGenericParameter )
1495
+ return ! printGenericTypeArgs ? string . Empty
1496
+ : ( printType ? . Invoke ( type , type . Name ) ?? type . Name ) ;
1497
+
1498
+ Type arrayType = null ;
1499
+ if ( type . IsArray )
1500
+ {
1501
+ // store the original type for the later and process its element type further here
1502
+ arrayType = type ;
1503
+ type = type . GetElementType ( ) ;
1504
+ }
1505
+
1493
1506
// the default handling of the built-in types
1507
+ string buildInTypeString = null ;
1494
1508
if ( type == typeof ( void ) )
1495
- return "void" ;
1509
+ buildInTypeString = "void" ;
1496
1510
if ( type == typeof ( object ) )
1497
- return "object" ;
1511
+ buildInTypeString = "object" ;
1498
1512
if ( type == typeof ( bool ) )
1499
- return "bool" ;
1513
+ buildInTypeString = "bool" ;
1500
1514
if ( type == typeof ( int ) )
1501
- return "int" ;
1515
+ buildInTypeString = "int" ;
1502
1516
if ( type == typeof ( short ) )
1503
- return "short" ;
1517
+ buildInTypeString = "short" ;
1504
1518
if ( type == typeof ( byte ) )
1505
- return "byte" ;
1519
+ buildInTypeString = "byte" ;
1506
1520
if ( type == typeof ( double ) )
1507
- return "double" ;
1521
+ buildInTypeString = "double" ;
1508
1522
if ( type == typeof ( float ) )
1509
- return "float" ;
1523
+ buildInTypeString = "float" ;
1510
1524
if ( type == typeof ( char ) )
1511
- return "char" ;
1525
+ buildInTypeString = "char" ;
1512
1526
if ( type == typeof ( string ) )
1513
- return "string" ;
1527
+ buildInTypeString = "string" ;
1514
1528
1515
- var isArray = type . IsArray ;
1516
- if ( isArray )
1517
- type = type . GetElementType ( ) ;
1529
+ if ( buildInTypeString != null )
1530
+ return printType ? . Invoke ( arrayType ?? type , buildInTypeString ) ?? buildInTypeString ;
1518
1531
1519
- var typeString = stripNamespace ? type . Name : type . FullName ?? type . Name ;
1532
+ var parentCount = 0 ;
1533
+ for ( var ti = type . GetTypeInfo ( ) ; ti . IsNested ; ti = ti . DeclaringType . GetTypeInfo ( ) )
1534
+ ++ parentCount ;
1520
1535
1521
- typeString = typeString . Replace ( '+' , '.' ) ; // handling the nested types
1536
+ Type [ ] parentTypes = null ;
1537
+ if ( parentCount > 0 )
1538
+ {
1539
+ parentTypes = new Type [ parentCount ] ;
1540
+ var pt = type . DeclaringType ;
1541
+ for ( var i = 0 ; i < parentTypes . Length ; i ++ , pt = pt . DeclaringType )
1542
+ parentTypes [ i ] = pt ;
1543
+ }
1522
1544
1523
1545
var typeInfo = type . GetTypeInfo ( ) ;
1524
- if ( ! typeInfo . IsGenericType )
1546
+ Type [ ] typeArgs = null ;
1547
+ var isTypeClosedGeneric = false ;
1548
+ if ( type . IsGenericType )
1525
1549
{
1526
- if ( printType != null )
1527
- typeString = printType . Invoke ( type , typeString ) ;
1528
- return isArray ? typeString + "[]" : typeString ;
1550
+ isTypeClosedGeneric = ! typeInfo . IsGenericTypeDefinition ;
1551
+ typeArgs = isTypeClosedGeneric ? typeInfo . GenericTypeArguments : typeInfo . GenericTypeParameters ;
1529
1552
}
1530
1553
1554
+ var typeArgsConsumedByParentsCount = 0 ;
1531
1555
var s = new StringBuilder ( ) ;
1532
- var tickIndex = typeString . IndexOf ( '`' ) ;
1533
- if ( tickIndex == - 1 )
1534
- s . Append ( typeString ) ;
1535
- else
1536
- s . Append ( typeString . Substring ( 0 , tickIndex ) ) ;
1537
-
1538
- s . Append ( '<' ) ; // todo: handling the generics in the nested type
1556
+ if ( ! stripNamespace )
1557
+ s . Append ( type . Namespace ) . Append ( '.' ) ;
1539
1558
1540
- var genericArgs = typeInfo . GetGenericTypeParametersOrArguments ( ) ;
1541
- if ( typeInfo . IsGenericTypeDefinition )
1542
- s . Append ( ',' , genericArgs . Length - 1 ) ;
1543
- else
1544
- for ( var i = 0 ; i < genericArgs . Length ; i ++ )
1545
- ( i > 0 ? s . Append ( ", " ) : s ) . Append ( genericArgs [ i ] . ToCode ( stripNamespace , printType ) ) ;
1559
+ if ( parentTypes != null )
1560
+ {
1561
+ for ( var p = parentTypes . Length - 1 ; p >= 0 ; -- p )
1562
+ {
1563
+ var parentType = parentTypes [ p ] ;
1564
+ var parentTypeInfo = parentType . GetTypeInfo ( ) ;
1546
1565
1547
- s . Append ( '>' ) ;
1566
+ if ( ! parentType . IsGenericType )
1567
+ {
1568
+ s . Append ( parentType . Name ) . Append ( '.' ) ;
1569
+ }
1570
+ else
1571
+ {
1572
+ Type [ ] parentTypeArgs = null ;
1573
+ if ( parentTypeInfo . IsGenericTypeDefinition )
1574
+ {
1575
+ parentTypeArgs = parentTypeInfo . GenericTypeParameters ;
1576
+
1577
+ // replace the open parent args with the closed child args,
1578
+ // and close the parent
1579
+ if ( isTypeClosedGeneric )
1580
+ for ( var t = 0 ; t < parentTypeArgs . Length ; ++ t )
1581
+ parentTypeArgs [ t ] = typeArgs [ t ] ;
1582
+
1583
+ var parentTypeArgCount = parentTypeArgs . Length ;
1584
+ if ( typeArgsConsumedByParentsCount > 0 )
1585
+ {
1586
+ int ownArgCount = parentTypeArgCount - typeArgsConsumedByParentsCount ;
1587
+ if ( ownArgCount == 0 )
1588
+ parentTypeArgs = null ;
1589
+ else
1590
+ {
1591
+ var ownArgs = new Type [ ownArgCount ] ;
1592
+ for ( var a = 0 ; a < ownArgs . Length ; ++ a )
1593
+ ownArgs [ a ] = parentTypeArgs [ a + typeArgsConsumedByParentsCount ] ;
1594
+ parentTypeArgs = ownArgs ;
1595
+ }
1596
+ }
1597
+ typeArgsConsumedByParentsCount = parentTypeArgCount ;
1598
+ }
1599
+ else
1600
+ {
1601
+ parentTypeArgs = parentTypeInfo . GenericTypeArguments ;
1602
+ }
1603
+
1604
+ var parentTickIndex = parentType . Name . IndexOf ( '`' ) ;
1605
+ s . Append ( parentType . Name . Substring ( 0 , parentTickIndex ) ) ;
1606
+
1607
+ // The owned parentTypeArgs maybe empty because all args are defined in the parent's parents
1608
+ if ( parentTypeArgs ? . Length > 0 )
1609
+ {
1610
+ s . Append ( '<' ) ;
1611
+ for ( var t = 0 ; t < parentTypeArgs . Length ; ++ t )
1612
+ ( t == 0 ? s : s . Append ( ", " ) )
1613
+ . Append ( parentTypeArgs [ t ] . ToCode ( stripNamespace , printType , printGenericTypeArgs ) ) ;
1614
+ s . Append ( '>' ) ;
1615
+ }
1616
+ s . Append ( '.' ) ;
1617
+ }
1618
+ }
1619
+ }
1620
+
1621
+ if ( typeArgs != null && typeArgsConsumedByParentsCount < typeArgs . Length )
1622
+ {
1623
+ var tickIndex = type . Name . IndexOf ( '`' ) ;
1624
+ s . Append ( type . Name . Substring ( 0 , tickIndex ) ) . Append ( '<' ) ;
1625
+ for ( var i = 0 ; i < typeArgs . Length - typeArgsConsumedByParentsCount ; ++ i )
1626
+ ( i == 0 ? s : s . Append ( ", " ) )
1627
+ . Append ( typeArgs [ i + typeArgsConsumedByParentsCount ]
1628
+ . ToCode ( stripNamespace , printType , printGenericTypeArgs ) ) ;
1629
+ s . Append ( '>' ) ;
1630
+ }
1631
+ else
1632
+ {
1633
+ s . Append ( type . Name ) ;
1634
+ }
1548
1635
1549
- if ( isArray )
1636
+ if ( arrayType != null )
1550
1637
s . Append ( "[]" ) ;
1551
1638
1552
- typeString = s . ToString ( ) ;
1553
- return printType ? . Invoke ( type , typeString ) ?? typeString ;
1639
+ return printType ? . Invoke ( arrayType ?? type , s . ToString ( ) ) ?? s . ToString ( ) ;
1554
1640
}
1555
1641
1556
1642
/// Prints valid C# Boolean
0 commit comments