2010-07-28

Exploring the GAC with F# and Mono.Cecil

Mono.Cecil can be used to look inside assemblies. May be you want to search GAC to find types that implement a certain interface. In this post, I’ll show how to find all the types that implement IDisposable as an example.

The output of this code on my machine:

There are 1620 DLLs in C:\Windows\assembly.
There are 365 DLLs in C:\Windows\Microsoft.NET\assembly.
# of public types: 30071
# IDisposable: 733

The code:

open System
open System.IO
open Mono.Cecil
 
let windir = Environment.GetFolderPath Environment.SpecialFolder.Windows
let pathGac2 = Path.Combine(windir, "assembly")
let pathGac4 = Path.Combine(windir, @"Microsoft.NET\assembly")
 
let main() =
  let dlls2 = Directory.EnumerateFiles(pathGac2, "*.dll", SearchOption.AllDirectories)
  let dlls4 = Directory.EnumerateFiles(pathGac4, "*.dll", SearchOption.AllDirectories)
 
  printfn "There are %d DLLs in %s." (Seq.length dlls2) pathGac2
  printfn "There are %d DLLs in %s." (Seq.length dlls4) pathGac4
 
  let readModule (dll:string) = ModuleDefinition.ReadModule dll
 
  let publicTypes =
    dlls4
    |> Seq.map readModule
    |> Seq.map (fun m -> m.Types)
    |> Seq.concat
    |> Seq.filter (fun t -> t.IsPublic)
 
  // How many public types in all .NET 4 assemblies?
  publicTypes |> Seq.length |> printfn "# of public types: %d"
 
  // How many of those implement the IDisposable interface?
  let isFullNameEqual (t:Type) (tr:TypeReference) = t.FullName = tr.FullName
  publicTypes
  |> Seq.filter (fun t -> t.Interfaces |> Seq.exists (isFullNameEqual typeof<IDisposable>))
  |> Seq.length |> printfn "# IDisposable: %d"
  ()
 
main()

A source release of the latest version of Mono.Cecil can be downloaded here. I built 0.9.3 for .NET 4 Client Profile in the Release configuration without issue.