Part 3: Analysis and Exploration

Part 1 of this series guided you through selecting an edition of .NET Reflector, installing it, and getting started with both the Reflector Desktop and the Visual Studio plugin. This article begins a comprehensive exploration of the key features of .NET Reflector, both natively and with enhancements provided by add-ins developed by the active Reflector community.

Part 2 covers the “meat and potatoes”, i.e. viewing, filtering, navigating, and debugging. Part 3 goes further into analyzing and exploring assemblies, showing you how to “slice and dice” to get to what you need. Part 4 rounds out the review of features explaining how to exercise the code in front of you or even any arbitrary code on the fly, as well as comparing and managing assemblies. The final part is a one-page companion wallchart that summarizes every feature in parts 2 through 4 and illustrates the key points of navigation in Reflector.

Select Disassembly Language

Reflector Desktop: Reflector’s toolbar has a language dropdown that lets you select IL (intermediate language), C#, Visual Basic, MC++, or F#. There are also add-ins available to supplement this list. You can change this dropdown setting before or after you view source code of an assembly. If you already have the source window open when you change the language, Reflector will immediately update it to the new language.

VS Extension: Within Visual Studio you have several ways to decompile and view foreign source—see the View code without source feature above. The first time you attempt to access source for a given assembly, Reflector decompiles it then displays it. With this dynamic decompilation, however, Reflector always decompiles into C# regardless of the language of your project (supporting other languages from dynamic decompilation is on Red Gate’s “to do” list but not a priority because the overwhelming majority of current users work in C#).

You can also explicitly decompile an assembly first before you ask to display the source. There are two ways to do this. If you choose the Enable Debugging context menu choice in the .NET Reflector object browser or in the VS solution explorer, it will still decompile into the same language as your current project. There is just one pathway to decompile to a different language: choose the Generate PDBs… menu choice. Select the library of interest then select the target language in the Decompilation Language dropdown. Note that unlike the Reflector Desktop you are limited to either C# or Visual Basic.

Convert Between .NET Languages

Reflector Desktop: Have you ever had a legacy project that you wanted to convert from Visual Basic to C#? If you read the Select disassembly language feature you already know how to begin this process: set your target language in the language dropdown then load the compiled assembly (or executable) in Reflector. Select the assembly in the assembly browser then export the source for the assembly by menu (File >>Export Assembly Source Code), context menu (menu >>Export Source Code), or keyboard (Ctrl+S) to write out all the source files of the assembly into a new file tree.

Note that if you have the associated documentation file (e.g. assembly.XML) this process does not reintegrate the doc-comments back into the code; there is, however, a Reflector add-in available—Denis Bauer’s File Disassembler—that does!

It’s worth noting also that Reflector hasn’t really been designed for this use case and it isn’t heavily supported, so you won’t necessarily get perfect converted code that compiles and runs without a hitch. Reflector is best treated as a translation aid here than a one-stop solution.

Decompile Multiple Assemblies at one time

Reflector Desktop: When you open the dialog to read an assembly (File >> Open Assembly… menu choice or Ctrl+O) you can use the standard .NET mechanism to select multiple files from the open file dialog: Shift+click to select a range of contiguous files in the same directory, or Ctrl+click to select non-contiguous files.

VS Extension: Once you have decompiled an assembly you can then view, step through, and set breakpoints in the generated source code just as if you were working with your own solution’s code. Note, however, that this applies only to the one assembly you have decompiled. If you attempt to step into code in a different assembly that you have not yet enabled for debugging, Visual Studio prompts you to enable it. Unfortunately, if you are in the middle of debugging that would lead to you having to stop debugging, enable the assembly for debugging, then restart debugging and work your way back to the point where you were interrupted. To avoid this interruption, you can prepare all your assemblies before you start the debugging session. You can do this individually in the .NET Reflector object browser, or you can do them all at once via the (.NET Reflector >> Generate PDBs…) menu choice. That opens a dialog allowing you to select all the assemblies you might want to debug then decompile them all at once.

Select Framework Version

Reflector Desktop: Just as you can change the language of the decompiled code, you can instantly translate your code between .NET framework versions with a dropdown selector on the toolbar. The current version supports .NET 1.0, 2.0, 3.5, 4.0, and 4.5. You may or may not see any obvious changes when you switch from one to another depending on what code you happen to have scrolled into view. However, if you have something like this in .NET 3.5, defining an auto-implemented property...

public List<string> Details { get; privateset; }

...it will change to this when you retarget to .NET 2.0 (because auto-implemented properties did not exist until C# 3.0):

VS Extension: Within Visual Studio you can change the target language version rather than the target framework version. They are of course related, but the relationship is not so simple to grok. The prolific Jon Skeet has an excerpt from his C# in Depth book online, Untangling the Versions, that enumerates the framework versions and the C# versions. These are loosely correlated in his final list of Visual Studio versions. The .NET Framework Evolution Map gives another helpful perspective, a chart tying the framework and language versions together. As to Visual Basic, Visual Basic and .NET Framework Versions is dated, but has a good diagram up to VB9/framework 3.5. From all those and other sources I have derived the simple table at the right to show the correspondence between framework versions and language versions.

To change the language version you use precisely the same means that you saw to change target language (see Select disassembly language). That is, you cannot let Reflector disassemble automatically; you must explicitly disassemble via the Generate PDBs... menu choice. In the dialog, select the library of interest, the target language (C# or Visual Basic) in the Decompilation Language dropdown, and finally the language version in the Version dropdown. Reflector currently supports versions 8.0, 9.0, 10.0, and 11.0 for Visual Basic, and versions 2.0, 3.0, 4.0, and 4.5 for C# (that last should really be 5.0, not 4.5, a little bug I raised with the team).

View Code Documentation

Reflector Desktop: The .NET framework supports annotating source code with documentation comments using a specific XML dialect designed for the purpose. If you do this in your own code, then you can generate formatted documentation from those doc-comments using Sandcastle (or Sandcastle Help File Builder if you want to do it more easily). Reflector provides its own formatting engine that accomplishes the same thing on the fly—when you decompile code you also get formatted documentation for the code provided you satisfy these conditions:

You have the documentation file (library.XML) for the third-party library (library.DLL).

You installed the documentation file in the same directory as the DLL.

You have set Reflector’s documentation display option to Formatted (which is the default).

If you satisfy these conditions you will automatically see a documentation panel when you view source code; both source and documentation panels are actually subpanels of the same main panel.

Alternately, you can view the doc-comments in their original, native format if you set Reflector’s documentation display option to XML Comments instead of the default (Tools >> Options >> Disassembler >> Documentation). With this option set, Reflector actually re-integrates the doc-comments exactly where they came from in the source code!

View Dependencies (text list)

Reflector Desktop: Invoke the dependency analyzer by menu (Tools >> Analyze), context menu (Analyze), or keyboard (Ctrl+R). This opens the dependency panel in Reflector’s main window, listing one or more of the dependencies categories listed across the top of Table 3 based on the item type you have selected.

Item

Depends on

Used By

Referenced By

Exposed By

Instantiated By

P/Invoke Imports

Assembly

•

•

•

Namespace

•

Class

•

•

•

•

Struct

•

•

•

•

Delegate

•

•

•

•

Property

•

•

Method

•

•

Table 2 Dependencies displayed for each item category.

Note that the dependency panel is not dynamically linked to your selection in the assembly browser. In contrast, the decompilation panel and the signature panel are dynamically linked so when you change your selection those panels change at the same time. The contents of the dependency panel are static, generated just at the time you invoke the analyzer. And in fact, if you then select a different item in the assembly browser and run the analyzer on that, it is added to the end of the list of items in the dependency panel, allowing you to then browse as many items as you care to include. Because it continues to accumulate items each time you invoke the analyzer, you can delete individual items either from context menu (menu >> Remove) or keyboard (Del). The quickest way to delete the entire list is to simply close the panel. The next time you invoke the analyzer it will re-open with only the item you have just selected.

VS Extension: Within Visual Studio, there is no specific support for viewing dependencies. However, by examining the standard list of project references displays the same list as the Depends On list for the desktop.

View Dependencies (graph)

Reflector Desktop: The Assembly Visualizer add-in from Denis Markelov provides several graphical perspectives, including one to view assembly dependencies as a directed graph. Reflector’s native capability to display a list of dependencies for a single assembly is a great starting point—see View dependencies (text list)—but this add-in gives you a great perspective of multiple assemblies at once. Once you install the add-in—see the discussion under Extending Reflector—you will have several new context menu entries to access different views provided by Assembly Visualizer. To view the dependency graph, select the top-level node of one of the assemblies of interest in the assembly browser, then select Browse Dependencies from the context menu. Assembly Visualizer then analyzes that assembly and all its interconnections—and I do mean all, going through every nook and cranny of the .NET framework. It opens with a diagram like that in the top panel of Figure 1, which is impressive but not terribly useful. In this example, I had loaded interconnected assemblies from my CleanCode open-source library and wanted to see what the add-in would do with them. Given the available controls of the add-in I quickly realized the best approach was one of elimination: I used the search capability (Point 1 in Figure 1) to identify all framework assemblies by just typing “System”. When you start typing you can then select all the assemblies found by just pressing enter in the search box (Point 2). Once selected, use Remove Selected to delete all those to remove the clutter (Point 3), leaving just the ones of interested in the lower panel. You can also rearrange the graph just by dragging, as I did to get the nice top-to-bottom ordering shown in the figure.

View Ancestry

Reflector Desktop: The Assembly Visualizer add-in from Denis Markelov helps you here too. Figure 2—borrowed from Markelov’s web page—shows ancestry for a WPF Control, tracing it all the way up (or down, depending on your point of view:-) to Object. Each intervening class may be expanded or collapsed to view its inherited members. Once you install the add-in—see the discussion under Extending Reflector—you will have several new context menu entries to access different views provided by Assembly Visualizer. To view the ancestry, select a type (class) in the assembly browser, then select Browse Ancestry from the context menu.

View Type Hierarchy

Reflector Desktop: The Assembly Visualizer add-in lets you view the hierarchy of a type as a directed graph, i.e. all types that are derived from a given type.

Reflector’s native dependency listing—see View dependencies (text list)—includes an Instantiated by category for classes that should, in theory, provide the same information but this add-in gives you a great visual perspective. Once you install the add-in—see the discussion under Extending Reflector—you will have several new context menu entries to access different views provided by Assembly Visualizer.

To view the hierarchy of a type, select a type (class) in the assembly browser, then select Visualize Descendants from the context menu. The top panel in Figure 3 shows the result for the framework type TraceListener, interesting because it has three direct descendants plus three others once removed for a total of six descendants. If you select Back to Search (so named because often you get here from the Search view), you get the hierarchy summarized, as indicated in the lower panel of the figure.

To open the search view directly, select a top-level assembly node in Reflector’s assembly browser and select Browse Assembly from its context menu.

Extract Resources from an Assembly

Reflector Desktop: Reflector lets you save regenerated source code for any assembly by menu (File >>Export Assembly Source Code), context menu (menu >>Export Source Code), or keyboard (Ctrl+S). If your project includes resources it saves those as well into a file with a .resources suffix. For things like string resources, those are accessible within the XML of the .resources file, but binary resources like image bitmaps need further manipulation. You can use a standalone utility such as Jason Haley’s Resource File Extractor or Josh Smith’s Embedded Image Grabber to extract individual images from a .resource file. Note that there are Reflector plugins available that sound like they might be able to streamline this a bit—FileGenerator or Resource Extractor come to mind—but they only do what Reflector does, save the .resources file.

More…

This concludes an examination of the second group of Reflector features. Refer to the companion wallchart to see the full list, and continue with the details in part 4.

Michael Sorens is passionate about software to be more productive, evidenced by his open source libraries in several languages (see his API bookshelf) as well as SqlDiffFramework (a DB comparison tool for heterogeneous systems including SQL Server, Oracle, and MySql). With degrees in computer science and engineering he has worked the gamut of companies from Fortune 500 firms to Silicon Valley startups over the last 25 years or so.
Current passions include PowerShell, .NET, SQL, and XML technologies (see his full brand page).
Spreading the seeds of good design wherever possible, he enjoys sharing knowledge via writing (see his full list of articles), teaching, and StackOverflow. Like what you have read? Connect with Michael on LinkedIn and Google +