🌟 .NET ExpandoObject 技术原理解析
引用 :
.NET 剖析4.0上ExpandoObject动态扩展对象原理 风潇潇人渺渺 快意刀山中草
ExpandoObject
IDynamicMetaObjectProvider
IEnumerable
字段_dict
IDictionary
嵌套类ExpandoMetaObject
DynamicMetaObject
方法Set/Get/Invoke
绑定方法BindGetMember等
反射方法缓存
🧠 一、总体架构设计(核心组件分析)
1.1 类关系拓扑图
创建
继承
实现
实现
«sealed»
ExpandoObject
+IDictionary _dict
+IDynamicMetaObjectProvider.GetMetaObject()
+IEnumerable.GetEnumerator()
+IEnumerable.GetEnumerator()
ExpandoMetaObject
-IDictionary dict
+BindGetMember(GetMemberBinder) : DynamicMetaObject
+BindSetMember(SetMemberBinder, DynamicMetaObject) : DynamicMetaObject
+BindInvokeMember(InvokeMemberBinder, DynamicMetaObject[]) : DynamicMetaObject
-Get(string, object) : object
-Set(string, object) : object
-Invoke(string, object) : object
«abstract»
DynamicMetaObject
+Expression Expression
+BindingRestrictions Restrictions
+object Value
+BindGetMember(GetMemberBinder) : DynamicMetaObject
+BindSetMember(SetMemberBinder, DynamicMetaObject) : DynamicMetaObject
+BindInvokeMember(InvokeMemberBinder, DynamicMetaObject[]) : DynamicMetaObject
IDynamicMetaObjectProvider
IEnumerable<string>
1.2 核心数据流架构
数据存储
执行层
DLR层
用户层
属性访问
属性设置
方法调用
Dict读写
线程同步
最终结果
构建表达式树
创建DynamicMetaObject
DLR执行引擎
实际调用Set/Get/Invoke
操作字典数据
GetMemberBinder
SetMemberBinder
InvokeMemberBinder
ExpandoMetaObject.BindGetMember
ExpandoMetaObject.BindSetMember
ExpandoMetaObject.BindInvokeMember
操作类型
动态操作
🛠 二、动态绑定机制深度解析
2.1 元对象提供器实现原理
DynamicMetaObject IDynamicMetaObjectProvider. GetMetaObject ( Expression express)
{ return new ExpandoMetaObject ( this , express) ;
}
DLR运行时 ExpandoObject ExpandoMetaObject 请求MetaObject(Expression) 创建ExpandoMetaObject(this, express) 返回ExpandoMetaObject实例 调用绑定方法(BindGetMember等) 返回DynamicMetaObject(表达式树) 编译执行表达式树 DLR运行时 ExpandoObject ExpandoMetaObject
2.2 表达式树构建技术
绑定方法
InvokeMember调用
创建表达式树
Expression.Call
目标对象: this
方法: Set/Get/Invoke
参数1: key常量
参数2: value常量
实际表达式树创建代码:
private DynamicMetaObject InvokeMember ( string key, MethodInfo met, params object [ ] values)
{ object args = null ; if ( met == invoke) args = values; else if ( values != null && values. Length > 0 ) args = values[ 0 ] ; return new DynamicMetaObject ( Expression. Call ( Expression. Constant ( this ) , met, Expression. Constant ( key, typeof ( string ) ) , Expression. Convert ( Expression. Constant ( args) , typeof ( object ) ) ) , BindingRestrictions. GetTypeRestriction ( base . Expression, base . LimitType) ) ;
}
🔍 三、成员操作深度分析
3.1 属性获取机制(Get)
用户代码 DLR运行时 ExpandoMetaObject 字典_dict var value = obj.Name BindGetMember("Name") 调用InvokeMember("Name", getMethod) 返回表达式树 编译并执行表达式树 调用Get("Name", null) lock(_dict) 返回dict["Name"] 抛出MemberAccessException alt [存在键] [不存在键] 返回结果 返回value 用户代码 DLR运行时 ExpandoMetaObject 字典_dict
3.2 属性设置机制(Set)
3.3 方法调用机制(Invoke)
调用Invoke方法
成员存在?
检查类型
检查
BindInvokeMember
参数转换:
收集所有参数
参数转换
InvokeMember:
传递方法名和参数
InvokeMember
构建表达式树
返回DynamicMetaObject
执行表达式树
获取锁
检查成员存在
存在
获取值
不存在
抛出异常
是委托?
是:
动态调用
否:
抛MethodAccessException
DynamicInvoke
返回结果
🔒 四、线程安全与锁机制
4.1 锁的应用全景图
潜在问题
安全访问
锁保护区域
返回原始迭代器
在枚举期间修改字典可能导致异常
临界区操作
字典存在检查
键值读取
键值设置
委托获取
键集合枚举
lock(_dict)
Get操作
Set操作
Invoke操作
枚举操作
4.2 改进后的锁策略
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 字典操作 锁保护 反射方法缓存 枚举器快照 枚举安全 无锁字典 减少锁范围 委托缓存 原始实现 优化建议 关键改进点 线程安全优化方案
改进后枚举实现:
IEnumerator< string > IEnumerable< string > . GetEnumerator ( )
{ lock ( _dict) { return new List< string > ( _dict. Keys) . GetEnumerator ( ) ; }
}
⚡ 五、性能优化深度分析
5.1 反射优化策略
原始实现
每次绑定调用GetMethod
运行时反射
高开销
优化建议
静态构造函数预加载
MethodInfo缓存
减少运行时开销
private static class MethodCache
{ public static readonly MethodInfo SetMethod; public static readonly MethodInfo GetMethod; public static readonly MethodInfo InvokeMethod; static MethodCache ( ) { SetMethod = typeof ( ExpandoMetaObject ) . GetMethod ( "Set" , BindingFlags. NonPublic | BindingFlags. Instance) ; }
}
5.2 表达式树编译缓存
第一次调用
构建表达式树
编译为委托
执行委托
后续调用
使用缓存委托
5.3 内存占用分析
45% 25% 15% 10% 5% 内存占用分布 字典存储 表达式树 元数据开销 委托对象 其他
🆚 六、与官方实现对比分析
6.1 架构差异对比图
mindmaproot((架构差异))线程同步🟢 此实现:全局lock🔵 官方实现:无锁CAS成员枚举🔴 此实现:原始迭代器🟢 官方实现:键集合快照元数据处理🟠 此实现:每次构建🟢 官方实现:缓存优化动态方法🟢 两者相同:基于委托错误处理🟠 此实现:基本异常🟢 官方实现:详细异常信息
6.2 性能基准对比
🛡 七、最佳实践与安全性
7.1 线程安全使用模式
只读线程
读写线程
创建ExpandoObject
写入初始化数据
多线程访问
安全
外部同步
使用外部锁
避免嵌套锁
7.2 异常处理体系
«异常体系»
DynamicExceptions
+MemberAccessException: 成员不存在
+MethodAccessException: 非委托调用
+TargetInvocationException: 委托异常
+InvalidOperationException: 枚举修改
MemberAccessException
MethodAccessException
TargetInvocationException
InvalidOperationException
🔮 八、高级应用场景
8.1 动态工作流引擎集成
条件满足
条件不满足
JSON配置
解析为ExpandoObject
动态添加方法
创建工作流
执行步骤
判断条件
执行下一节点
执行备选分支
8.2 动态规则引擎实现
用户 规则API 规则引擎 ExpandoObject 定义规则({condition: "Age >= 18", action: "Approve"}) 添加规则(规则对象) 提交请求(用户数据) 转换为动态对象 添加验证方法 条件结果 执行对应操作 alt [条件验证] 返回结果 loop [执行规则] 用户 规则API 规则引擎 ExpandoObject
💎 九、总结与展望
9.1 技术实现矩阵
9.2 未来发展建议
- .NET Core优化 =等 this[key]访问 分段锁策略 基于ImmutableDictionary 支持+ 缓存MethodInfo 返回快照 预编译动态方法 基础优化 缓存MethodInfo 反射优化 返回快照 枚举安全 分段锁策略 减少锁竞争 高级特性 this[key]访问 索引器支持 支持+ - =等 动态操作符 .NET Core优化 跨平台兼容 性能突破 基于ImmutableDictionary 无锁实现 预编译动态方法 AOT支持 ExpandoObject进化路线