@@ -62,19 +62,19 @@ public static StringBuilder ToILString(this MethodInfo method, StringBuilder s =
6262 var secondLine = false ;
6363 foreach ( var il in ilReader )
6464 {
65- try
65+ try
6666 {
67- if ( secondLine )
67+ if ( secondLine )
6868 s . AppendLine ( ) ;
69- else
69+ else
7070 secondLine = true ;
7171 s . Append ( il . Offset . ToString ( ) . PadRight ( 4 , ' ' ) ) . Append ( ' ' ) . Append ( il . OpCode ) ;
7272 if ( il is InlineFieldInstruction f )
73- s . Append ( ' ' ) . Append ( f . Field . DeclaringType . Name ) . Append ( '.' ) . Append ( f . Field . Name ) ;
73+ s . Append ( ' ' ) . AppendTypeName ( f . Field . DeclaringType ) . Append ( '.' ) . Append ( f . Field . Name ) ;
7474 else if ( il is InlineMethodInstruction m )
75- s . Append ( ' ' ) . Append ( m . Method . DeclaringType . Name ) . Append ( '.' ) . Append ( m . Method . Name ) ;
75+ s . Append ( ' ' ) . AppendTypeName ( m . Method . DeclaringType ) . Append ( '.' ) . Append ( m . Method . Name ) ;
7676 else if ( il is InlineTypeInstruction t )
77- s . Append ( ' ' ) . Append ( t . Type ? . Name ) ;
77+ s . Append ( ' ' ) . AppendTypeName ( t . Type ) ;
7878 else if ( il is InlineTokInstruction tok )
7979 s . Append ( ' ' ) . Append ( tok . Member . Name ) ;
8080 else if ( il is InlineBrTargetInstruction br )
@@ -112,4 +112,163 @@ public static StringBuilder ToILString(this MethodInfo method, StringBuilder s =
112112 return s ;
113113 }
114114
115+ public static StringBuilder AppendTypeName ( this StringBuilder sb , Type type , bool stripNamespace = false ) =>
116+ type == null ? sb : sb . Append ( type . TypeToCode ( stripNamespace ) ) ;
117+
118+ public static string TypeToCode ( this Type type ,
119+ bool stripNamespace = false , Func < Type , string , string > printType = null , bool printGenericTypeArgs = true )
120+ {
121+ if ( type . IsGenericParameter )
122+ return ! printGenericTypeArgs ? string . Empty : ( printType ? . Invoke ( type , type . Name ) ?? type . Name ) ;
123+
124+ if ( Nullable . GetUnderlyingType ( type ) is Type nullableElementType && ! type . IsGenericTypeDefinition )
125+ {
126+ var result = nullableElementType . TypeToCode ( stripNamespace , printType , printGenericTypeArgs ) + "?" ;
127+ return printType ? . Invoke ( type , result ) ?? result ;
128+ }
129+
130+ Type arrayType = null ;
131+ if ( type . IsArray )
132+ {
133+ // store the original type for the later and process its element type further here
134+ arrayType = type ;
135+ type = type . GetElementType ( ) ;
136+ }
137+
138+ // the default handling of the built-in types
139+ string buildInTypeString = null ;
140+ if ( type == typeof ( void ) )
141+ buildInTypeString = "void" ;
142+ else if ( type == typeof ( object ) )
143+ buildInTypeString = "object" ;
144+ else if ( type == typeof ( bool ) )
145+ buildInTypeString = "bool" ;
146+ else if ( type == typeof ( int ) )
147+ buildInTypeString = "int" ;
148+ else if ( type == typeof ( short ) )
149+ buildInTypeString = "short" ;
150+ else if ( type == typeof ( byte ) )
151+ buildInTypeString = "byte" ;
152+ else if ( type == typeof ( double ) )
153+ buildInTypeString = "double" ;
154+ else if ( type == typeof ( float ) )
155+ buildInTypeString = "float" ;
156+ else if ( type == typeof ( char ) )
157+ buildInTypeString = "char" ;
158+ else if ( type == typeof ( string ) )
159+ buildInTypeString = "string" ;
160+
161+ if ( buildInTypeString != null )
162+ {
163+ if ( arrayType != null )
164+ buildInTypeString += "[]" ;
165+ return printType ? . Invoke ( arrayType ?? type , buildInTypeString ) ?? buildInTypeString ;
166+ }
167+
168+ var parentCount = 0 ;
169+ for ( var ti = type . GetTypeInfo ( ) ; ti . IsNested ; ti = ti . DeclaringType . GetTypeInfo ( ) )
170+ ++ parentCount ;
171+
172+ Type [ ] parentTypes = null ;
173+ if ( parentCount > 0 )
174+ {
175+ parentTypes = new Type [ parentCount ] ;
176+ var pt = type . DeclaringType ;
177+ for ( var i = 0 ; i < parentTypes . Length ; i ++ , pt = pt . DeclaringType )
178+ parentTypes [ i ] = pt ;
179+ }
180+
181+ var typeInfo = type . GetTypeInfo ( ) ;
182+ Type [ ] typeArgs = null ;
183+ var isTypeClosedGeneric = false ;
184+ if ( type . IsGenericType )
185+ {
186+ isTypeClosedGeneric = ! typeInfo . IsGenericTypeDefinition ;
187+ typeArgs = isTypeClosedGeneric ? typeInfo . GenericTypeArguments : typeInfo . GenericTypeParameters ;
188+ }
189+
190+ var typeArgsConsumedByParentsCount = 0 ;
191+ var s = new StringBuilder ( ) ;
192+ if ( ! stripNamespace && ! string . IsNullOrEmpty ( type . Namespace ) ) // for the auto-generated classes Namespace may be empty and in general it may be empty
193+ s . Append ( type . Namespace ) . Append ( '.' ) ;
194+
195+ if ( parentTypes != null )
196+ {
197+ for ( var p = parentTypes . Length - 1 ; p >= 0 ; -- p )
198+ {
199+ var parentType = parentTypes [ p ] ;
200+ if ( ! parentType . IsGenericType )
201+ {
202+ s . Append ( parentType . Name ) . Append ( '.' ) ;
203+ }
204+ else
205+ {
206+ var parentTypeInfo = parentType . GetTypeInfo ( ) ;
207+ Type [ ] parentTypeArgs = null ;
208+ if ( parentTypeInfo . IsGenericTypeDefinition )
209+ {
210+ parentTypeArgs = parentTypeInfo . GenericTypeParameters ;
211+
212+ // replace the open parent args with the closed child args,
213+ // and close the parent
214+ if ( isTypeClosedGeneric )
215+ for ( var t = 0 ; t < parentTypeArgs . Length ; ++ t )
216+ parentTypeArgs [ t ] = typeArgs [ t ] ;
217+
218+ var parentTypeArgCount = parentTypeArgs . Length ;
219+ if ( typeArgsConsumedByParentsCount > 0 )
220+ {
221+ int ownArgCount = parentTypeArgCount - typeArgsConsumedByParentsCount ;
222+ if ( ownArgCount == 0 )
223+ parentTypeArgs = null ;
224+ else
225+ {
226+ var ownArgs = new Type [ ownArgCount ] ;
227+ for ( var a = 0 ; a < ownArgs . Length ; ++ a )
228+ ownArgs [ a ] = parentTypeArgs [ a + typeArgsConsumedByParentsCount ] ;
229+ parentTypeArgs = ownArgs ;
230+ }
231+ }
232+ typeArgsConsumedByParentsCount = parentTypeArgCount ;
233+ }
234+ else
235+ {
236+ parentTypeArgs = parentTypeInfo . GenericTypeArguments ;
237+ }
238+
239+ var parentTickIndex = parentType . Name . IndexOf ( '`' ) ;
240+ s . Append ( parentType . Name . Substring ( 0 , parentTickIndex ) ) ;
241+
242+ // The owned parentTypeArgs maybe empty because all args are defined in the parent's parents
243+ if ( parentTypeArgs ? . Length > 0 )
244+ {
245+ s . Append ( '<' ) ;
246+ for ( var t = 0 ; t < parentTypeArgs . Length ; ++ t )
247+ ( t == 0 ? s : s . Append ( ", " ) ) . Append ( parentTypeArgs [ t ] . TypeToCode ( stripNamespace , printType , printGenericTypeArgs ) ) ;
248+ s . Append ( '>' ) ;
249+ }
250+ s . Append ( '.' ) ;
251+ }
252+ }
253+ }
254+ var name = type . Name . TrimStart ( '<' , '>' ) . TrimEnd ( '&' ) ;
255+
256+ if ( typeArgs != null && typeArgsConsumedByParentsCount < typeArgs . Length )
257+ {
258+ var tickIndex = name . IndexOf ( '`' ) ;
259+ s . Append ( name . Substring ( 0 , tickIndex ) ) . Append ( '<' ) ;
260+ for ( var i = 0 ; i < typeArgs . Length - typeArgsConsumedByParentsCount ; ++ i )
261+ ( i == 0 ? s : s . Append ( ", " ) ) . Append ( typeArgs [ i + typeArgsConsumedByParentsCount ] . TypeToCode ( stripNamespace , printType , printGenericTypeArgs ) ) ;
262+ s . Append ( '>' ) ;
263+ }
264+ else
265+ {
266+ s . Append ( name ) ;
267+ }
268+
269+ if ( arrayType != null )
270+ s . Append ( "[]" ) ;
271+
272+ return printType ? . Invoke ( arrayType ?? type , s . ToString ( ) ) ?? s . ToString ( ) ;
273+ }
115274}
0 commit comments