2

我正在尝试从 .NET 类型中获取 Mono.Cecil TypeDefinition 并且没有任何运气。

我正在使用这样的代码:

var type = typeof(MarkdownMonster.AppConfiguration);

var a = AssemblyDefinition.ReadAssembly(type.Assembly.Location);
var tr = a.MainModule.Import(type);  // this seems to work
var td = tr.Resolve(); // fails

但它因程序集解析错误而失败:

GetConfigurationPropertiesTest [0:29.990] 失败:Mono.Cecil.AssemblyResolutionException:无法解析程序集:'MarkdownMonster,Version=1.18.11.0,Culture=neutral,PublicKeyToken=null' Mono.Cecil.AssemblyResolutionException:无法解析程序集:'MarkdownMonster, Version=1.18.11.0,Culture=neutral,PublicKeyToken=null' at Mono.Cecil.BaseAssemblyResolver.Resolve(AssemblyNameReference name, ReaderParameters parameters) at Mono.Cecil.DefaultAssemblyResolver.Resolve(AssemblyNameReference name) at Mono.Cecil.MetadataResolver.Resolve( TypeReference 类型)在 Mono.Cecil.TypeReference.Resolve() 在 Westwind.TypeImporter.TypeParser.ParseObject(Type type, Boolean dontParseMembers)

程序集显然在那里,因为 TypeReference 导入似乎工作并产生了有效的 TypeReference。

有问题的程序集是一个 EXE,只是为了好玩,我将它重命名为 DLL,但这没有任何效果。

4

1 回答 1

1

经过一番反复试验,我发现一个(丑陋的)解决方案是创建一个自定义类型解析器,并基本上强制对其进行硬类型引用。一旦找到主程序集,似乎 Mono.Cecil 能够解决瞬态依赖关系,但不是顶级引用。

为了完成这项工作,我基本上传递了已经解决的程序集参考。就我而言,我知道我需要返回的唯一参考将是顶级参考,所以我对此进行了硬编码。一个更现实的例子将不得不使用AssemblyDefinition.ReadAssembly()从磁盘或流中读取程序集。

下面是创建 AssemblyResolver 的代码:

    public class MonoAssemblyResolver : IAssemblyResolver
    {
        public AssemblyDefinition AssemblyDefinition;

        public AssemblyDefinition Resolve(AssemblyNameReference name)
        {
            return AssemblyDefinition;
        }

        public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
        {

            return AssemblyDefinition;
        }

        public void Dispose()
        {
            AssemblyDefinition = null;
        }
    }

请注意传递已解决的程序集引用的作弊。

要解决,我现在可以使用以下代码:

var a = AssemblyDefinition.ReadAssembly(type.Assembly.Location,
            new ReaderParameters() { AssemblyResolver = resolver });

// assign the resolvedr
var resolver = new MonoAssemblyResolver();
resolver.AssemblyDefinition = a;

var tr = a.MainModule.Import(type: type);
var td = tr.Resolve();   // works now

这是疯狂的hacky,但可以适应更通用(在我的情况下不需要)。

如果 Mono.Cecil 可以自动解析程序集,它仍然会更好 - 我不明白为什么它没有首先找到程序集,因为它位于当前的 bin 文件夹中并且 TypeReference 可以找到它。

于 2019-08-15T23:27:25.673 回答