You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用System.Reflection.Emit实现INotifyPropertyChanged时触发InvalidProgramException

问题分析与解决方案

System.InvalidProgramException 这类运行时错误,几乎都是手动生成的IL代码存在语法或逻辑错误导致的——因为Reflection.Emit不会像C#编译器那样帮你做语法校验,哪怕IL代码逻辑错了,编译阶段也不会报错,只有运行时才会触发异常。结合你的场景,问题大概率出在INotifyPropertyChanged事件的实现,或者属性set方法中调用OnPropertyChanged的IL逻辑里。

可能的错误点及检查方向

1. OnPropertyChanged方法的IL实现错误

OnPropertyChanged是触发通知的核心方法,常见错误包括:

  • 事件null检查逻辑错误:比如没有先判断PropertyChanged事件是否为null就直接调用Invoke,或者IL指令顺序颠倒(比如先调用Invoke再做null判断)。
  • PropertyChangedEventArgs实例创建错误:没有正确获取该类型的构造函数,或者传递参数时栈操作错误。
  • 委托调用错误:调用PropertyChangedEventHandler.Invoke时,参数顺序或数量不对(需要传递this和PropertyChangedEventArgs实例)。

正确的OnPropertyChangedIL逻辑示例:

// 加载当前实例(this)
ldarg.0
// 获取PropertyChanged事件的字段引用
ldfld class [System.ComponentModel]System.ComponentModel.PropertyChangedEventHandler YourDynamicClass::PropertyChanged
// 如果事件为null,跳转到结束标签
brfalse.s SKIP_INVOKE
// 重新加载this
ldarg.0
// 加载传入的propertyName参数
ldarg.1
// 创建PropertyChangedEventArgs实例
newobj instance void [System.ComponentModel]System.ComponentModel.PropertyChangedEventArgs::.ctor(string)
// 调用委托的Invoke方法
callvirt instance void [System.ComponentModel]System.ComponentModel.PropertyChangedEventHandler::Invoke(object, class [System.ComponentModel]System.ComponentModel.PropertyChangedEventArgs)
SKIP_INVOKE:
// 方法返回
ret

2. 属性set方法中调用OnPropertyChanged的IL错误

set方法里的常见问题:

  • 通知调用顺序错误:还没把新值保存到字段就触发了通知,或者栈操作不平衡(比如加载了多余的参数,导致栈顶元素数量不符合方法调用要求)。
  • 属性名字符串传递错误:比如没有正确加载属性名的字符串常量到栈上,或者传递了空字符串/错误的属性名。

正确的set方法IL逻辑示例:

// 加载this
ldarg.0
// 加载传入的属性新值
ldarg.1
// 将新值保存到对应的字段
stfld object YourDynamicClass::_yourPropertyField
// 加载this,准备调用OnPropertyChanged
ldarg.0
// 加载属性名的字符串常量
ldstr "YourPropertyName"
// 调用OnPropertyChanged方法
call instance void YourDynamicClass::OnPropertyChanged(string)
// 方法返回
ret

3. INotifyPropertyChanged接口的实现错误

  • 事件定义不规范:比如没有正确用EventBuilder创建PropertyChanged事件,或者事件的add/remove方法逻辑错误(比如没有正确维护委托链)。
  • 接口实现未正确关联:动态类没有正确实现INotifyPropertyChanged接口,比如没有显式实现接口的事件成员。

排查建议

  1. 用反编译工具(如dnSpy)加载生成的动态程序集,查看动态类的IL代码,对比手动编写的INotifyPropertyChanged实现,找出IL指令的差异。
  2. 重点检查栈操作:确保每个IL指令执行后栈的状态符合预期(比如调用方法前栈上的参数数量和类型必须匹配方法签名)。
  3. 分步验证:先单独测试动态类的属性赋值和通知触发逻辑,再绑定到Avalonia DataGrid,缩小问题范围。

内容的提问来源于stack exchange,提问作者Guillermo Espert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 04:33:21