В дополнение к тому, что предложил JB Evain, этот код поможет избежать исключения. Все, что вам нужно сделать, это обработать исключение в resolver.
Не лучший способ, я признаю. Но это работает для этого сценария: "If I am decompiling a DLL on a system where the referred assemblies are not present, the decompilation fails (with exception.) At least, i would like to see the decompile code, for whatever has been resolved."
using System;
using System.Collections.Generic;
using Mono.Cecil;
public class MyAssemblyResolver : BaseAssemblyResolver
{
private readonly IDictionary<string, AssemblyDefinition> cache;
public MyAssemblyResolver()
{
this.cache = new Dictionary<string, AssemblyDefinition>(StringComparer.Ordinal);
}
public override AssemblyDefinition Resolve(AssemblyNameReference name)
{
if (name == null)
throw new ArgumentNullException("name");
AssemblyDefinition assemblyDefinition = null;
if (this.cache.TryGetValue(name.FullName, out assemblyDefinition))
return assemblyDefinition;
try //< -------- My addition to the code.
{
assemblyDefinition = base.Resolve(name);
this.cache[name.FullName] = assemblyDefinition;
}
catch { } //< -------- My addition to the code.
return assemblyDefinition;
}
protected void RegisterAssembly(AssemblyDefinition assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
string fullName = assembly.Name.FullName;
if (this.cache.ContainsKey(fullName))
return;
this.cache[fullName] = assembly;
}
}
И используйте это так:
var rp = new Mono.Cecil.ReaderParameters() { AssemblyResolver = new MyAssemblyResolver() };
var assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(assemblyStream, rp);
var astBuilder = new ICSharpCode.Decompiler.Ast.AstBuilder(
new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule));
astBuilder.AddAssembly(assemblyDefinition);
Я бы хотел увидеть улучшение в декомпиляторе: в данный момент он игнорирует ReaderParameters
, заданный пользователем, в классе DefaultAssemblyResolver
.
Использование:
var rp = new Mono.Cecil.ReaderParameters();
var assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(assemblyStream, rp);
Текущий DefaultAssemblyResolver
код:
public override AssemblyDefinition Resolve(AssemblyNameReference name)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
AssemblyDefinition assemblyDefinition;
if (this.cache.TryGetValue(name.FullName, out assemblyDefinition))
{
return assemblyDefinition;
}
assemblyDefinition = base.Resolve(name); // <---------
// Is the `ReaderParameters` object set by user, used to resolve in `base` class?
this.cache[name.FullName] = assemblyDefinition;
return assemblyDefinition;
}