Decompiling Anonymous Method IL in .NET Core

戏子无情 提交于 2020-01-16 04:26:06

问题


I have this method

public void Add(Action<Cursor> action)
{
    // Decompile `action` to C#
}

Inside the method I want to decompile the anonymous method inside action to C# code, or AST representation of C# code.

I tried using Mono.Cecil and ICSharpCode.Decompiler (from the ILSpy repository), but I couldn't find a way to decompile anonymous methods, as both libraries require you to load the assembly from a physical location and search the method through the types graph, which seems very convoluted, especially when looking for an anonymous method.

Is there a way use the IL Byte array of the method, and decompile that to C#?

public void Add(Action<Cursor> action)
{
    var il = action.Method.GetMethodBody().GetILAsByteArray();
    var ast = decompiler.DecompileIL(il); // Does such decompiler exist?
}

回答1:


Using the ICSharpCode.Decompiler library (from the ILSpy repository), I was able to decompile a lambda method.

Like this

public void Add(Action<Cursor> action)
{
    // Get the assembly in which the lambda resides
    var asm = Assembly.GetCallingAssembly();
    var file = asm.Location;

    // Create a resolver (a callback for resolving referenced assemblies during decompilation)
    var resolver = new CustomAssemblyResolver(asm);
    // Create an instance of decompiler
    var decompiler = new CSharpDecompiler(file, resolver, new DecompilerSettings());

    // Get an "EntityHandle" instance for the lambda's underlying method
    var method = MetadataTokenHelpers.TryAsEntityHandle(action.Method.MetadataToken); 

    var ast = decompiler.Decompile(new List<EntityHandle>() { method.Value });
}

As I mentioned, you provide the CSharpDecompiler instance with a resolver (IAssemblyResolver) whose job is to load referenced assemblies during the decompilation process.

ICSharpCode.Decompiler has a UniversalAssemblyResolver (source) which does the job by searching common folders in the file system (it receives a framework version to know where to search). I didn't like it as it assumes too much and requires too much information (I don't always know the framework or other parts of my runtime), so I've created my own resolver which traverses the assemblies graph (starting from the calling assembly).

class CustomAssemblyResolver : IAssemblyResolver
{
    private Dictionary<string, Assembly> _references;

    public CustomAssemblyResolver(Assembly asm)
    {
        _references = new Dictionary<string, Assembly>();
        var stack = new Stack<Assembly>();
        stack.Push(asm);

        while (stack.Count > 0)
        {
            var top = stack.Pop();
            if (_references.ContainsKey(top.FullName)) continue;

            _references[top.FullName] = top;

            var refs = top.GetReferencedAssemblies();
            if (refs != null && refs.Length > 0)
            {
                foreach (var r in refs)
                {
                    stack.Push(Assembly.Load(r));
                }
            }
        }

        ;
    }

    public PEFile Resolve(IAssemblyReference reference)
    {
        var asm = _references[reference.FullName];
        var file = asm.Location;
        return new PEFile(file, new FileStream(file, FileMode.Open, FileAccess.Read), PEStreamOptions.Default, MetadataReaderOptions.Default);
    }

    public PEFile ResolveModule(PEFile mainModule, string moduleName)
    {
        var baseDir = Path.GetDirectoryName(mainModule.FileName);
        var moduleFileName = Path.Combine(baseDir, moduleName);
        if (!File.Exists(moduleFileName))
        {
            throw new Exception($"Module {moduleName} could not be found");
        }
        return new PEFile(moduleFileName, new FileStream(moduleFileName, FileMode.Open, FileAccess.Read), PEStreamOptions.Default, MetadataReaderOptions.Default);
    }
}

I don't know if it's the best approach for all use cases, but It works great for me, at least so far.



来源:https://stackoverflow.com/questions/57231579/decompiling-anonymous-method-il-in-net-core

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!