Speed Up Your Reflection Processes, Page 5
Line 10 opens an exception handling block, emitting a try. Line 11 is the opcode that translates to loading the methods first (or zero-th) argument. Line 12 calls the virtual method referenced by the MethodInfo variable enumer, which from Listing 6 you know is GetEnumerator. The code is setting up code that is roughly a while loop iterating over the list of Customers. Line 13 stores the IEnumerator returned by GetEnumerator into the local variable emitted on Line 5.
Lines 14 and 15 define labels for branching statements. Yes, GOTO is a love while in MSIL and assembly language. This is how things like break an dcontinue are implemented. Line 16 is an unconditional branch to the location of label IL_003f. (The labels were named based on approximations and by looking at how Visual Studio compilers VB into MSIL. You can use any name you'd like.)
The MarkLabel command on Line 17 demonstrates how to place a label. OpCodes.LdLoc_1 (or whatever number suffix) are used to load the local parameters onto the evaluation stack. Lines 18 and 19 use the enumerator to get the Current object—the Customer. Because get_Current returns an object type, Line 18 casts the type of the current object to the type of T and stires it in the first parameter.
Lines 23 to 35 use basic Reflection and repeat emitted code that emits the property name and the property value. The if-condition starting on Line 30 checks to see whether the type is a a value type. Value types are things like integers that you wouldn't normally think of as classes, but by boxing them .NET permits you to treat them like classes. In this case, both referenced classes and value types are treated like object so that ToString can be called on every property value regardless of whether it's a reference type or value type.
The rest of the code moves the enumerator and supports ending the loop. Line 49 contains the finally block that cleans up the enumerator by calling Dispose and contains the return statement.
Loading and Calling the Dynamic Code
The final three lines create an instance of the type contained in the typeBuilder. The second to the last line saves the assembly with a unique name, and the remaining line uses Reflection to invoke the behavior.
For a generally useful dynamic assembly, you will want to return a reference to the TypeBuilder or just know when your code has created a dynamic assembly. The key here is that, once you create a dynamic assembly and load it using Reflection.Emit, it stays in memory in your AppDomain—and is available but never unloaded—until your application stops running. Figure 1 shows the CustomerDumper.dll—the dynamic assembly created by the code from Listing 3—as one of your applications loaded modules.
Figure 1: One challenge with dynamically emitted assemblies is that they remain loaded as long as your application is running.
It's worth noting that you don't have to become an MSIL expert to get some benefit from Reflection.Emit. A handy trick is to write the code you ultimately want to emit in VB and then use ILDASM to see what kind of MSIL you need to emit. Use sparingly and in situations where you need to eke out some performance; emitting MSIL dynamically can help you get a lot of mileage out of your solutions.
Reflection.Emit lets you emit MSIL—.NET's equivalent of assembly language—at runtime. Use this technique when you have a problem that is best solved by a single, general algorithm, but pure Reflection is too slow. Instead, write a single, general emitter that dynamically emits the hard-code equivalent for you. You get the best of both worlds: You write a single algorithm and .NET emits code as if you had written a specialized algorithm for each need.
About the Author
Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming and .NET. Check out his upcoming book LINQ Unleashed for C# now available on Amazon.com and fine bookstores everywhere. Look for his upcoming book Teach Yourself the ADO.NET Entity Framework in 24 Hours. You may contact him for technology questions at email@example.com.
Copyright © 2008 by Paul T. Kimmel. All Rights Reserved.