|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThis article originated from the need to find out the methods, fields and properties that an assembly accesses through its references. While Visual Studio shows the list of assemblies that an assembly references, it does not show the actual members being referenced. FindRefs is a simple tool that uses Cecil [^] as the back-end to analyze all methods and properties in an assembly and list the method calls, field and property references made by it on types residing in referenced assemblies. BackgroundThe motivation to write the tool was to figure out the logical dependencies of an assembly, so that refactoring or redesigning its referenced assemblies would not break it. Just the list of referenced assemblies wasn't obviously enough and I couldn't find any tool, except Reflector, that gave me the list of methods, properties and fields that are actually referenced. However, I couldn't find a way to export the output from Reflector and so I decided to roll my own. Besides, I had just discovered Cecil and I thought this would be a nice opportunity to play around with it. Using FindRefsUsing FindRefs is very simple. FindRefs is a command line application that takes the assembly to be analyzed as the argument. You could optionally filter the types to be considered (for output) using the findrefs <assembly_path> [-include filterlist] [-exclude filterlist]</assembly_path>
// excludes all types in all namespaces under System
findrefs blah.exe -exclude System.*
// excludes all types in all namespaces/types under System except for System.Console
findrefs blah.exe -include System.Console -exclude System.*
// excludes everything except System.Console
findrefs blah.exe -include System.Console -exclude *
// excludes all types except those whose fully qualified names start with Sys
findrefs blah.exe -include Sys* -exclude *
The output will be written to blah.xml (the assembly name without the extension + .xml) and it gets generated in the current directory. Not specifying Sample OutputFor a simple program like: class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello");
}
}
Running findrefs on the compiled assembly generates the following output: <?xml version="1.0" encoding="utf-8"?>
<References>
<Assembly name="mscorlib, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089">
<Type name="System.Console">
<Reference name="System.Void System.Console::WriteLine(System.String)" />
</Type>
<Type name="System.Object">
<Reference name="System.Void System.Object::.ctor()" />
</Type>
</Assembly>
</References>
How It WorksThe Cecil library makes it really simple to walk through all methods in an assembly. You load the assembly and get a reference to public static void FindReferences(string assemblyPath, TypeFilter typeFilter)
{
AssemblyDefinition assemblyDefinition = AssemblyFactory.GetAssembly(assemblyPath);
foreach (ModuleDefinition moduleDefinition in assemblyDefinition.Modules)
{
Console.WriteLine("Processing module [" + moduleDefinition.Name + "]");
foreach (TypeDefinition typeDefinition in moduleDefinition.Types)
{
ProcessType(typeDefinition, typeFilter);
}
}
}
static void ProcessType(TypeDefinition typeDefinition, TypeFilter typeFilter)
{
Console.WriteLine("Processing type [" + typeDefinition.FullName + "]");
foreach (MethodDefinition methodDefinition in typeDefinition.Methods)
{
ProcessMethod(methodDefinition, typeFilter);
}
foreach (MethodDefinition methodDefintion in typeDefinition.Constructors)
{
ProcessMethod(methodDefintion, typeFilter);
}
foreach (PropertyDefinition propertyDefintion in typeDefinition.Properties)
{
ProcessMethod(propertyDefintion.GetMethod, typeFilter);
ProcessMethod(propertyDefintion.SetMethod, typeFilter);
}
}
The rest of the code is just plumbing to group the results by assembly and type. There is also code that groups the references by the calling method, but that data is not used currently. ConclusionThis was my first brush with the Mono project and I must say I was really impressed by Cecil [^]. It was incredibly easy figuring out how to use it and it seems to handle .NET 2.0 stuff like generics pretty well. Anyway, I had great fun writing this tool and I hope it proves to be a useful addition to CP's repository of free tools. Comments, suggestions (and bug reports:)) welcome. History
|
|||||||||||||||||||||||||||||||||||||||||||||||