删除方法后从 PEVerify 获取“类型加载失败”

Posted

技术标签:

【中文标题】删除方法后从 PEVerify 获取“类型加载失败”【英文标题】:Getting "Type load failed" from PEVerify after removing methods 【发布时间】:2017-05-29 04:46:47 【问题描述】:

短篇小说

我正在使用以下 Mono.Cecil 代码从接口和实现该接口的类中删除除了几个方法之外的所有方法。

static void Main(string[] args)

    var moduleDef = ModuleDefinition.ReadModule("SomeService.dll");

    var bigService = moduleDef.Types.Single(t => t.Name == "BigService"); // interface
    var bigServiceClient = moduleDef.Types.Single(t => t.Name == "BigServiceClient"); // class implementing above interface
    var toSave = new[] "method1", "method2";

    SaveMethods(bigService, toSave);
    SaveMethods(bigServiceClient, toSave);

    moduleDef.Write(@"C:\AutobooksCode\MAIN\API\JHA\JHA.SymXchange.V2\bin\Release\JHA.SymXchange.V2_updated.dll");


private static void SaveMethods(TypeDefinition typeDef, string[] names)

    var methodsToSave = typeDef.Methods.Where(m => names.Contains(m.Name, StringComparer.OrdinalIgnoreCase)).ToList();
    var ctors = typeDef.Methods.Where(m => m.Name == ".ctor");

    methodsToSave.AddRange(ctors);

    // remove all methods except the ones I want to save
    var pos = 0;
    while (true)
    
        if (typeDef.Methods.Count == methodsToSave.Count)
            break;

        if (methodsToSave.Contains(typeDef.Methods[pos]))
            pos++;
        else
        
            typeDef.Methods.RemoveAt(pos);
        
    

代码工作正常,ILDASM 和 JustDecompile 看起来一切都很好,最重要的是,DLL 可以很好地与客户端配合使用。但是,通过 PEVerify 运行它会为 [token 0x02001C35] 生成一个 Type load failed. 错误。

我使用ILDASM /TOK 来查看哪个令牌是 0x02001C35,它是我正在修改的类 (BigServiceClient)。我就是看不出是什么问题。

关于如何进一步调查 PEVerify 错误的任何指针/想法/提示?

长篇大论

我正在使用旧版 SOAP 接口。我使用svcutil 来生成代理,但是由于这个接口的遗留特性,这些代理是巨大的——就像单个类中的 1500 多个方法一样。这导致了对象创建以及 Castle DynamicProxy 代理的一些性能问题。

作为快速测试,我从生成的 .cs 代理文件中删除了我需要的所有方法(是的,仅 1500 多个中的 2 个),重新编译并获得了很多更好的结果。时间从 6-7 秒缩短到 20 毫秒以下。

编辑这些文件以手动删除它很乏味,所以我想我会用 Mono.Cecil 自动化它。如上所述,一切正常,但我担心 peverify 错误。

我知道你可以用 IL 编织做一些非常复杂和疯狂的事情,但我只需要删除一堆未使用的方法。是的,我可以手动解析生成的源代码并将其从那里删除,但如果您曾经见过从 svcutil 生成的 SOAP 代理,那么我想避免这条路径。

【问题讨论】:

【参考方案1】:

发现问题。具有讽刺意味的是,我在编写代码以手动处理源文件并对其进行修剪时发现了这一点。 :)

在编写源文件处理器时,我注意到svcutil 生成了两个implicit interface implementation as well as an explicit interface implementation。我之前的SaveMethods 代码过于激进并删除了显式实现。我怀疑这是导致 PEVerify 出现 Type load failed 错误的原因。

这是我更新的 SaveMethods 实现,它生成了一个成功完成 PEVerify 的程序集:

private static void SaveMethods(TypeDefinition typeDef, IEnumerable<string> names)

    var pos = 0;
    while (true)
    
        if (pos == typeDef.Methods.Count)
            break;

        var md = typeDef.Methods[pos];

        // save ctors, method implementations and explicit interface implementations
        if (md.Name == ".ctor" ||
            names.Contains(md.Name) ||
            (md.Overrides.Count > 0 && names.Contains(md.Overrides[0].Name)))
        
            pos++;
        
        else
        
            typeDef.Methods.RemoveAt(pos);
        
    

【讨论】:

以上是关于删除方法后从 PEVerify 获取“类型加载失败”的主要内容,如果未能解决你的问题,请参考以下文章

如何添加多个视图和删除视图并在删除后从视图中获取所有数据?

在 Swift 中 segue 后从堆栈中删除(删除)视图/视图控制器的正确方法

推送后从远程删除已提交文件的最佳方法

dataguard主库删除归档日志后从库恢复的方法

Meteor - 如何在特定时间段后从服务器端方法中自动从集合中删除单个项目?

密码正确后从 DataGridView 中删除选定的行