.NET ExpandoObject 技术原理解析

发布于:2025-07-15 ⋅ 阅读:(17) ⋅ 点赞:(0)

🌟 .NET ExpandoObject 技术原理解析

引用

  1. .NET 剖析4.0上ExpandoObject动态扩展对象原理
  2. 风潇潇人渺渺
  3. 快意刀山中草
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 架构差异对比图

mindmap
  root((架构差异))
    线程同步
      🟢 此实现:全局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支持
AOT支持
ExpandoObject进化路线

网站公告

今日签到

点亮在社区的每一天
去签到