引用不同版本NuGet时C# vtable变化及OnAppearing调用异常问题
问题分析与解答
为什么仅升级基础应用的UI库无效?
这是因为.NET平台中,类型的虚方法表(vtable)是在程序集编译阶段就固定下来的,不会在运行时动态更新。模块编译时依赖的是旧版UI库,此时ModuleBasePage的vtable结构已经确定;即便基础应用升级到新版UI库,模块的已编译程序集不会重新生成,它的vtable依然保持编译时的状态,自然不会调用新版LibraryBasePage里新增的OnAppearing修复逻辑。
两种场景下的vtable结构说明
(a) 模块和基础应用均升级UI库时
- 编译模块时,依赖的是已经重写了
ContentPage.OnAppearing的新版LibraryBasePage。 ModuleBasePage的vtable结构:- 先继承新版
LibraryBasePage的vtable条目,其中OnAppearing初始指向LibraryBasePage.OnAppearing; - 由于
ModuleBasePage重写了OnAppearing,vtable中对应的条目会被替换为ModuleBasePage.OnAppearing; - 当
ModuleBasePage的OnAppearing调用base.OnAppearing()时,会触发新版LibraryBasePage的修复逻辑,因为父类vtable里的OnAppearing指向的就是这个修复后的方法。
- 先继承新版
(b) 仅基础应用升级UI库时
- 模块编译时依赖的是旧版
LibraryBasePage,这个版本没有重写ContentPage.OnAppearing,所以旧版LibraryBasePage的vtable中,OnAppearing直接指向ContentPage.OnAppearing。 ModuleBasePage的vtable结构:- 编译时重写了
OnAppearing,vtable中对应的条目直接替换为ModuleBasePage.OnAppearing; - 模块的已编译程序集里,
ModuleBasePage的父类vtable信息还是旧版的——没有LibraryBasePage.OnAppearing这个条目; - 运行时,即便基础应用加载了新版
LibraryBasePage,ModuleBasePage的vtable链条里根本没有指向新版LibraryBasePage.OnAppearing的环节:调用base.OnAppearing()时,会直接跳到ContentPage.OnAppearing,完全不会触发新版UI库的修复逻辑,甚至新版LibraryBasePage.OnAppearing从来不会被调用。
- 编译时重写了
内容的提问来源于stack exchange,提问作者Christopher Stephan
相关产品推荐
相关产品推荐

