VB.Net - Reflection

Reflection is a category of logic used to practically reverse engineer (no that’s compute ;^) the object model contained in a DLL.

You see common uses like the object browser feature built into many programming environments.

I used it to generate most of the code contained in the Framework pages in the prior version of the Markland Central website. I have since removed those pages.

One complexity is that … well you could imagine a class definition being stored in an array object on steroids. The problem with this analogy is that a class could have methods, functions, properties, events… who knows what else. Consequently there’s lots and lots of methods, properties, and even classes that are used to query the object model.

Here are pieces of the code I used to construct my web pages

** Sample
The reflection reads data - not necessarily in alphabetic order, the intellisence data is kept in xml files.

This is a code sample which sift’s through framework objects, and pulls out it’s API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
'
' perhaps you can use the GetTypes function to get a list of all the data types
'
Dim strPath As String = "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\"
Dim strExt As String = ".dll"

Dim strNameSpaces() As String = _
{"System.Configuration.Install", "System.Data", "System.Data.OracleClient", "System.Design", _
"System.DirectoryServices", "System", "System.Drawing.Design", "System.Drawing", _
"System.EnterpriseServices", "System.Management", _
"System.Messaging", "System.Runtime.Remoting", "System.Runtime.Serialization.Formatters.Soap", _
"System.Security", "System.ServiceProcess", "System.Web", "System.Web.Mobile", _
"System.Web.RegularExpressions", "System.Web.Services", "System.Windows.Forms", "System.XML"}
' "System.EnterpriseServices.Thunk",

' Dim sz As String = ""
Dim sb As New System.Text.StringBuilder
Dim xmlDoc As Xml.XmlDocument

Dim xmlValid As Boolean

For Each strNameSpace As String In strNameSpaces
Dim anAssy As System.Reflection.Assembly
anAssy = System.Reflection.Assembly.LoadFrom( _
strPath & strNameSpace & strExt)

Try
xmlDoc = New Xml.XmlDocument
xmlDoc.Load(strPath & strNameSpace & ".xml")
xmlValid = True
Catch ex As Exception
xmlValid = False
End Try

Dim Types() As Type
Types = anAssy.GetTypes()

'sb = sb.Append("<br><br>Namespace: " & strNameSpace & "<br><br>")
For Each t As Type In Types
If t.IsPublic Then
sb = sb.Append("<B>Class: " & t.FullName & "</B> <br>")
Dim elem As Xml.XmlNode = xmlDoc.SelectSingleNode( _
"/doc/members/member[@name='T:" & t.FullName & "']")
If elem Is Nothing Then
' skip title
Else
If elem.InnerText.Length > 0 Then
sb = sb.Append("Summary:<br> ")
sb = sb.Append(elem.Item("summary").InnerXml)
sb = sb.Append("<br><br>")
End If
End If


'Dim Enums As System.Reflection.e

' get constructors
Dim Constructors() As System.Reflection.ConstructorInfo _
= t.GetConstructors()
If Constructors.Length > 0 Then
sb = sb.Append("Constructors:<br>")
For Each C As System.Reflection.ConstructorInfo In Constructors
sb = sb.Append("<B> " & C.TypeConstructorName & " ")
sb = ShowParameters(sb, C.GetParameters)
sb = sb.Append("</B> <br>")
Next
End If


Dim Properties() As System.Reflection.PropertyInfo _
= t.GetProperties()
If Properties.Length > 0 Then
'
' ohmygosh! it's not alphabetized. No problem we'll do that ourselves
'
Dim SortedPropertyList As New System.Collections.SortedList

sb = sb.Append("<br>Properties:<br>")
For Each p As System.Reflection.PropertyInfo In Properties
Dim sb2 As New System.Text.StringBuilder
sb2 = sb2.Append("<B>" & p.Name & " as " & p.PropertyType.ToString & "</B> <br>")

Dim PropertyComment As Xml.XmlNode = xmlDoc.SelectSingleNode( _
"/doc/members/member[@name='P:" & t.FullName & "." & p.Name & "']")
If PropertyComment Is Nothing Then
' skip title
Else
If PropertyComment.InnerText.Length > 0 Then
sb2 = sb2.Append(PropertyComment.Item("summary").InnerXml)
End If
End If
sb2 = sb2.Append("<br><br>")

' add the property we just defined to the sorted list
SortedPropertyList.Add(p.Name, sb2)
Next
' pick the properties out of the sorted list and add to our output
' but remember - we might have put in a stringbuilder but we're
' pulling out dictionaryentry objects.
For Each sb2 As System.Collections.DictionaryEntry In SortedPropertyList
sb = sb.Append(sb2)
Next
End If


Dim Methods() As System.Reflection.MethodInfo _
= t.GetMethods()
If Methods.Length > 0 Then
sb = sb.Append("<br>Methods:<br>")
Dim SortedPropertyList As New System.Collections.SortedList

For Each m As System.Reflection.MethodInfo In Methods
Dim sb2 As New System.Text.StringBuilder

sb2 = sb2.Append("<B>" & m.Name)
sb2 = ShowParameters(sb2, m.GetParameters)
If m.ReturnType.ToString <> "System.Void" Then
sb2 = sb2.Append(" as " & m.ReturnType.ToString)
End If
sb2 = sb2.Append("</B> <br>")

Dim aKey As String = ShowParameterTypes(m.GetParameters)
Dim methodComment As Xml.XmlNode = xmlDoc.SelectSingleNode( _
"/doc/members/member[@name='M:" & t.FullName & "." & m.Name & aKey & "']")
If methodComment Is Nothing Then
' skip title
Else
' we have something like
' <member name="M:System.Configuration.Install.Installer.Uninstall(System.Collections.IDictionary)">
' <summary>
' <para>When overridden in a derived class, removes an installation. </para>
' </summary>
' <param name="savedState">
' <para>An <see cref="T:System.Collections.IDictionary" /> that contains the state of the computer after the installation was complete. </para>
' </param>
' <exception cref="T:System.ArgumentException">The saved-state <see cref="T:System.Collections.IDictionary" /> might have been corrupted. </exception>
' <exception cref="T:System.Configuration.Install.InstallException">
' <para>An exception occurred while uninstalling. This exception is ignored and the uninstall continues. However, the application might not be fully uninstalled after the uninstallation completes.</para>
' </exception>
'</member>

If methodComment.InnerXml.Length > 0 Then
sb2 = sb2.Append("Summary:<br> ")

Dim strSummary As String _
= methodComment.Item("summary").InnerXml

Dim Parameters As Xml.XmlNodeList _
= methodComment.SelectNodes("param")
Dim strParameters As String = ""
If Parameters.Count > 0 Then
strParameters = "Parameters:<br>"
For Each aParameterDesc As Xml.XmlNode In Parameters
strParameters = strParameters _
& "* " & aParameterDesc.Attributes("name").Value _
& "-" & aParameterDesc.InnerXml & "<br>"
Next
End If

Dim Exceptions As Xml.XmlNodeList _
= methodComment.SelectNodes("exception")
Dim strException As String = ""
If Exceptions.Count > 0 Then
strException = "Potential Exceptions:<br>"
For Each anExceptionDesc As Xml.XmlNode In Exceptions
strException = strException _
& "* [[" & anExceptionDesc.Attributes("cref").Value _
& "]] - " & anExceptionDesc.InnerXml & "<br>"
Next
End If

sb2 = sb2.Append(strSummary & "<br>")
If strParameters <> "" Then
sb2 = sb2.Append(strParameters)
End If
If strException <> "" Then
sb2 = sb2.Append(strException)
End If
End If
End If
sb2 = sb2.Append("<br><br>")

SortedPropertyList.Add(m.Name, sb2)
Next
' pick the properties out of the sorted list and add to our output
' but remember - we might have put in a stringbuilder but we're
' pulling out dictionaryentry objects.
For Each sb2 As System.Collections.DictionaryEntry In SortedPropertyList
sb = sb.Append(sb2)
Next
End If


Dim Events() As System.Reflection.EventInfo _
= t.GetEvents()
If Events.Length > 0 Then
Dim SortedPropertyList As New System.Collections.SortedList

sb = sb.Append("<br>Events:<br>")
For Each ev As System.Reflection.EventInfo In Events
Dim sb2 As New System.Text.StringBuilder

sb2 = sb2.Append("<B>" & ev.Name)
sb2 = sb2.Append("(")
sb2 = sb2.Append(") as ")
sb2 = sb2.Append(ev.EventHandlerType.ToString)
sb2 = sb2.Append("</B> <br>")

Dim EventComment As Xml.XmlNode = xmlDoc.SelectSingleNode( _
"/doc/members/member[@name='E:" & t.FullName & "." & ev.Name & "']")
If EventComment Is Nothing Then
' skip title
Else
If EventComment.InnerText.Length > 0 Then
'sb = sb.Append("Summary:<br> ")
sb2 = sb2.Append(EventComment.InnerXml)
End If
End If
sb2 = sb2.Append("<br><br>")

' add the property we just defined to the sorted list
SortedPropertyList.Add(ev.Name, sb2)
Next
' pick the properties out of the sorted list and add to our output
' but remember - we might have put in a stringbuilder but we're
' pulling out dictionaryentry objects.
For Each sb2 As System.Collections.DictionaryEntry In SortedPropertyList
sb = sb.Append(sb2)
Next
End If

sb = sb.Append("<br><br><br>")
End If

Next
Next

sb = sb.Replace("<para>", "")
sb = sb.Replace("</para>", "<br>")
sb = sb.Replace("<exception cref=""", "[[")
sb = sb.Replace("<see cref=""", "[[")
sb = sb.Replace("<see langword=""", "[[")
sb = sb.Replace("<param name=""", "[[")
sb = sb.Replace(""">", "]]")
sb = sb.Replace(""" />", "]]")

sb = sb.Replace("<br>", vbCrLf)
sb = sb.Replace("<li>", vbCrLf & "* ")
sb = sb.Replace("</ul>", vbCrLf & vbCrLf)
txt.Text = sb.ToString
End Sub

Function ShowParameters( _
ByVal sb As System.Text.StringBuilder, _
ByVal x As System.Reflection.ParameterInfo()) _
As System.Text.StringBuilder

Dim NumParms As Integer = 0
If x.Length = 0 Then
sb = sb.Append("()")
Else
sb = sb.Append("(")
For Each pi As System.Reflection.ParameterInfo In x
If NumParms > 0 Then
sb = sb.Append(", ")
End If
NumParms = NumParms + 1
sb = sb.Append("")
If pi.IsOptional Then
sb = sb.Append("Optional ")
End If
sb = sb.Append(pi.Name & " as " & pi.ParameterType.ToString)
Next
sb = sb.Append(")")
End If
Return sb
End Function

Function ShowParameterTypes( _
ByVal x As System.Reflection.ParameterInfo()) _
As String

Dim sb As New System.Text.StringBuilder
Dim NumParms As Integer = 0

If x.Length = 0 Then
sb = sb.Append("()")
Else
sb = sb.Append("(")
For Each pi As System.Reflection.ParameterInfo In x
If NumParms > 0 Then
sb = sb.Append(", ")
End If
NumParms = NumParms + 1
sb = sb.Append("")
If pi.IsOptional Then
sb = sb.Append("Optional ")
End If
sb = sb.Append(pi.ParameterType.ToString)
Next
sb = sb.Append(")")
End If
Return sb.ToString
End Function

Note: On my computer this took quite a long time to run.
It used to take a minute. Then I added XML logic which gave the output descriptions. This added 15 minutes to the project. Then I added Sort logic - Yikes! we’re into 20 minutes now and it’s still running.