The Member Tree¶
Note
The documentation has a new home: Check it out!
Assemblies and modules¶
The root of every .NET assembly is represented by the AssemblyDefinition
class. This class exposes basic information such as name, version and public key token, but also a collection of all modules that are defined in the assembly. Modules are represented by the ModuleDefinition
class.
Below an example that enumerates all modules defined in an assembly.
var assembly = AssemblyDefinition.FromFile(...);
foreach (var module in assembly.Modules)
Console.WriteLine(module.Name);
Most .NET assemblies only have one module. This main module is also known as the manifest module, and can be accessed directly through the AssemblyDefinition.ManifestModule
property.
Obtaining types in a module¶
Types are represented by the TypeDefinition
class. To get the types defined in a module, use the ModuleDefinition.TopLevelTypes
property. A top level types is any non-nested type. Nested types are exposed through the TypeDefinition.NestedTypes
. Alternatively, to get all types, including nested types, it is possible to call the ModuleDefinition.GetAllTypes
method instead.
Below is an example program that iterates through all types recursively and prints them:
public const int IndentationWidth = 3;
private static void Main(string[] args)
{
var module = ModuleDefinition.FromFile(...);
DumpTypes(module.TopLevelTypes);
}
private static void DumpTypes(IEnumerable<TypeDefinition> types, int indentationLevel = 0)
{
string indentation = new string(' ', indentationLevel * IndentationWidth);
foreach (var type in types)
{
// Print the name of the current type.
Console.WriteLine("{0}- {1} : {2:X8}", indentation, type.Name, type.MetadataToken.ToInt32());
// Dump any nested types.
DumpTypes(type.NestedTypes, indentationLevel + 1);
}
}
Obtaining methods and fields¶
The TypeDefinition
class exposes collections of methods and fields that the type defines:
foreach (var method in type.Methods)
Console.WriteLine("{0} : {1:X8}", method.Name, method.MetadataToken.ToInt32());
foreach (var field in type.Fields)
Console.WriteLine("{0} : {1:X8}", field.Name, field.MetadataToken.ToInt32());
Methods and fields have a Signature
property, that contain the return and parameter types, or the field type respectively.
MethodDefinition method = ...
Console.WriteLine("Return type: " + method.Signature.ReturnType);
Console.WriteLine("Parameter types: " + string.Join(", ", method.Signature.ParameterTypes));
FieldDefinition field = ...
Console.WriteLine("Field type: " + field.Signature.FieldType);
However, for reading parameters from a method definition, it is preferred to use the Parameters
property instead of the ParameterTypes
property stored in the signature. This is because the Parameters
property automatically binds the types to the parameter definitions that are associated to these parameter types. This provides additional information, such as the name of the parameter:
foreach (var parameter in method.Parameters)
Console.WriteLine($"{parameter.Name} : {parameter.ParameterType}");
Obtaining properties and events¶
Obtaining properties and events is similar to obtaining methods and fields; TypeDefinition
exposes them in a list as well:
foreach (var @event in type.Events)
Console.WriteLine("{0} : {1:X8}", @event.Name, @event.MetadataToken.ToInt32());
foreach (var property in type.Properties)
Console.WriteLine("{0} : {1:X8}", property.Name, property.MetadataToken.ToInt32());
Properties and events have methods associated to them. These are accessible through the Semantics
property:
foreach (MethodSemantics semantic in property.Semantics)
{
Console.WriteLine("{0} {1} : {2:X8}", semantic.Attributes, semantic.Method.Name,
semantic.MetadataToken.ToInt32());
}