KirillOsenkov / MetadataTools

Various tools and helpers to read assembly metadata.
MIT License
178 stars 25 forks source link

MetadataTools

Included features:

Reading an assembly MVID

Mono.Cecil stripped down to a single file to read assembly MVID without dependencies.

Here are the various ways to retrieve the MVID of an assembly:

ImageReader

Just embed this file: https://github.com/KirillOsenkov/MetadataTools/blob/master/src/PEFile/ImageReader.cs

var mvid = ImageReader.ReadAssemblyMvid(filePath);

Cold run on a warm file: 7ms

Or see this sample from Roslyn: https://github.com/dotnet/roslyn/blob/1c98fe1fc6ef122cb3bb436aa90a0ea729fdcf37/src/Compilers/Core/MSBuildTask/MvidReader.cs#L13

Mono.Cecil

https://www.nuget.org/packages/Mono.Cecil

var module = Mono.Cecil.ModuleDefinition.ReadModule(filePath);
var mvid = module.Mvid;

Cold run on a warm file: 16ms

Reflection

This has the downside that it loads the assembly:

var assemblyName = AssemblyName.GetAssemblyName(filePath);
var assembly = Assembly.Load(assemblyName);
var mvid = assembly.ManifestModule.ModuleVersionId;

Cold run on a warm file: 33ms

System.Reflection.Metadata

https://www.nuget.org/packages/System.Reflection.Metadata

Sample in Roslyn: https://github.com/dotnet/roslyn/blob/1c98fe1fc6ef122cb3bb436aa90a0ea729fdcf37/src/Compilers/Core/Portable/AssemblyUtilities.cs#L84

using (var stream = File.OpenRead(filePath))
{
    PEReader reader = new PEReader(stream);
    var metadataReader = reader.GetMetadataReader();
    var mvidHandle = metadataReader.GetModuleDefinition().Mvid;
    var mvid = metadataReader.GetGuid(mvidHandle);
}

Cold run on a warm file: 76ms

BenchmarkDotNet paints quite a different performance picture:

               Method |        Mean |    StdDev |
--------------------- |------------ |---------- |
  ReadUsingReflection | 208.2023 us | 0.4036 us |
         ReadUsingSRM |  98.9620 us | 0.3674 us |
       ReadUsingCecil | 153.1947 us | 0.3085 us |
 ReadUsingImageReader | 147.0230 us | 1.2618 us |