Jim Meeker, who showed up at the latest WeProgram.Net user group meeting, points out Reflector for .Net at Lutz Roeder's site (http://www.aisto.com/roeder/dotnet/). This will let you search, disassemble, and otherwise get your hands dirty with MSIL.
This post complements a discussion we had in the ODU ITPro class the other evening; it gets into much more advanced topics than a 200 level course warrants, but for those interested folks out there, read on . . .
The .NET CLR (Common Language Runtime) is a bit like a cozy blanket wrapped around our business logic. Not only is it a class loader and execution environment for our .Net types, it facilitates various forms of security, cross-language compatibility, memory management, type safety . . . and this isn’t an exhaustive list. In fact, the CLR environment is better than just a blanket – it’s like an electric blanket with a hot chocolate machine and slippers built in!
Metadata is one of the ways the CLR achieves such a rich set of services to our .Net code. As programmers, we can leverage this metadata to interesting ends. If you want to follow along at home, add a button and a listbox to a windows form and include the following in the button click event (since I’m teaching a vb.net class currently, I opted for vb sample code – everything is essentially the same in c#):
Dim fileSys as New OpenFileDialog()
fileSys.Filter = "Executables ( *.exe )|*.exe|Assemblies ( *.dll )|*.dll"
fileSys.ShowDialog()
Dim assm As Reflection.Assembly = Reflection.Assembly.LoadFrom( fileSys.FileName )
The .Net Reflection namespace is a powerful mechanism for reading (and even writing!) assembly data. After calling Reflection.Assembly.LoadFrom(), our assm variable can tell us all about the assembly that we browsed to with the OpenFileDialog. Let’s add the following to our button click event code:
Dim arrTypes As Type() = assm.GetTypes()
Dim arrAttributes as Attribute()
Dim objType As Type
Dim objAtt As Attribute
Dim objCustAtt As MyAttribute ‘custom attribute
The above is just variable declarations, with the notable exception of the first line (assm.GetTypes()) where we assign all the types in the assembly to our arrTypes array. Assembly metadata contains detailed descriptions of the types our assembly exposes; Reflection, by using assm.GetTypes(), is our tool to reveal these types.
Now for the good part:
For Each objType In arrTypes
ListBox1.Items.Add( objType.FullName & " Summary" )
arrAttributes = Attribute.GetCustomAttributes( objType )
if arrAttributes.GetUpperBound( 0 ) > 0 then
For Each objAtt in arrAttributes
Try
ListBox1.Items.Add( objAtt.ToString() )
objCustAtt = CType( objAtt, MyAttribute )
ListBox1.Items.Add( "***Custom Value: " & objCustAtt.Value )
Catch
End Try
Next
End If
Next objType
Assuming we’ve got a listbox (named ListBox1), this code will interrogate the types in the assm assembly and display information about the type. If you run this sample on a .Net windows application you’ll see that there are a number of System.ComponentModel attributes at work. I won’t go into the functionality of those attributes because I want to focus on making our OWN attributes. Let’s add the following class to the project we’re creating:
<AttributeUsage( AttributeTargets.All )> _
Public Class MyAttribute
Inherits System.Attribute
private _strVal as String
Public ReadOnly Property Value as String
Get
return _strVal
End Get
End Property
Public Sub New( Value As String )
MyBase.New( )
_strVal = Value
End Sub
End Class
This is a simple example of a custom attribute with a single public property (named Value); it inherits from the System.Attribute class and uses an attribute of its own (in VB.Net, attributes are contained within < and > tags). With this class added to our project, we can include our custom attribute to any class definitions in our project as follows:
<MyAttribute( "Some Custom Data" )> _
Public Class Form1
Attributes must be on the same line as the class definition (note the line continuation character “_”).
If you run the program and select the exe that we added our custom attribute to, you’ll see the “Some Custom Data” text displayed in the listbox along with the other intrinsic .Net attributes.
Why is this significant? It allows us to extend .Net metadata and solve programming problems in different ways. .Net uses Attributes all over the place, two examples being to communicate security conditions and to control design-time behaviour of controls. In my company, we use custom attributes to map data objects to relational database objects (for ex: <DataFieldAttribute( “idProduct” ) >); this way we can decouple our object model from the database. Attributes can offer an elegant solution and, with Reflection and Metadata providing the tools, I recommend keeping an eye out for opportunities to make use of them. They aren’t always the answer, but custom attributes and Reflection are powerful enough to warrant your consideration.