ICSharpCode.Decompiler + Mono.Cecil -> How to generate code for a single method?
Asked Answered
C

2

5

I'm able to use Mono.Cecil and ICSharpCode.Decompiler to generate the code for a type or an assembly.

But if I try to generate the code for a single method I'll get an error "Object reference not set to an instance of an object."

Can you guys give me any hints about this? Thanks ahead for all the help.

Code to generate code for all the types inside an assembly:

DirectoryInfo di = new DirectoryInfo(appPath);
FileInfo[] allAssemblies = di.GetFiles("*.dll");
foreach (var assemblyFile in allAssemblies)
{
    string pathToAssembly = assemblyFile.FullName;
    System.Reflection.Assembly assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(pathToAssembly);
    Mono.Cecil.AssemblyDefinition assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(pathToAssembly,parameters);
    AstBuilder astBuilder = null;

    foreach (var typeInAssembly in assemblyDefinition.MainModule.Types)
    {
        if (typeInAssembly.IsPublic)
        {
             Console.WriteLine("T:{0}", typeInAssembly.Name);
            //just reset the builder to include only code for a single type
            astBuilder = new AstBuilder(new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule));
            astBuilder.AddType(typeInAssembly);
            StringWriter output = new StringWriter();
            astBuilder.GenerateCode(new PlainTextOutput(output));
            string result = output.ToString();
            output.Dispose();
        }
    }
}

Code to generate code for all the public methods inside an assembly:

DirectoryInfo di = new DirectoryInfo(appPath);
FileInfo[] allAssemblies = di.GetFiles("*.dll");
foreach (var assemblyFile in allAssemblies)
{
    string pathToAssembly = assemblyFile.FullName;
    System.Reflection.Assembly assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(pathToAssembly);
    Mono.Cecil.AssemblyDefinition assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(pathToAssembly,parameters);
    AstBuilder astBuilder = null;

    foreach (var typeInAssembly in assemblyDefinition.MainModule.Types)
    {
        if (typeInAssembly.IsPublic)
        {
            Console.WriteLine("T:{0}", typeInAssembly.Name);
            foreach (var method in typeInAssembly.Methods)
            {
                //just reset the builder to include only code for a single method
                astBuilder = new AstBuilder(new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule));
                astBuilder.AddMethod(method);
                if (method.IsPublic && !method.IsGetter && !method.IsSetter && !method.IsConstructor)
                {
                    Console.WriteLine("M:{0}", method.Name);
                    StringWriter output = new StringWriter();
                    astBuilder.GenerateCode(new PlainTextOutput(output));
                    string result = output.ToString();
                    output.Dispose();
                }
            }
        }
    }
}
Congregationalist answered 21/3, 2012 at 19:21 Comment(2)
Which line throws the exception?Pennebaker
Did you ever figure this out? I'm getting an exception as soon as I call AstBuilder.AddMethod...Grover
S
6

I had the same problem. You should set the property CurrentType of the DecompilerContext. Change your code to

astBuilder = new AstBuilder(new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule) { CurrentType = typeInAssembly } );
Sibbie answered 22/11, 2012 at 8:26 Comment(0)
I
3

When I recently implemented a quick C# decompiler (MonoDecompiler based), I used the ILSpy methods :)

public string getSourceCode(MethodDefinition methodDefinition)
{
    try
    {
        var csharpLanguage = new CSharpLanguage();
        var textOutput = new PlainTextOutput();
        var decompilationOptions = new DecompilationOptions();
        decompilationOptions.FullDecompilation = true;
        csharpLanguage.DecompileMethod(methodDefinition, textOutput, decompilationOptions);
        return textOutput.ToString();              

    }
    catch (Exception exception)
    {
        PublicDI.log.error("in getSourceCode: {0}", new object[] { exception.Message });
        return ("Error in creating source code from IL: " + exception.Message);
    }
}

For this and other examples see: https://github.com/o2platform/O2.Platform.Scripts/blob/master/3rdParty/MonoCecil/CecilDecompiler/CecilDecompiler.cs

The stand-alone mini C# decompilation tool is created by this script https://github.com/o2platform/O2.Platform.Scripts/blob/master/3rdParty/MonoCecil/Utils/Tool%20-%20C%23%20Quick%20Decompiler.h2

Insatiable answered 19/12, 2012 at 7:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.