0x03-ForEach 全面观
前面,我们已经了解组成一个 object visitor 最基本的部件以及最佳的性能做法。本篇我们来介绍一下更多关于 ForEach 方法的奇怪操作。
ForEach 的重载
ForEach 以下主要的重载形式:
ForEach(Expression<Action<IObjectVisitorContext<T, object>>> foreachAction)
ForEach(Expression<Action<string, object>> foreachAction)
ForEach<TValue>(Expression<Action<IObjectVisitorContext<T, TValue>>> foreachAction)
ForEach<TValue>(Expression<Action<string, TValue>> foreachAction)
这四个重在分别按照“泛型”和“使用 Context”两两交叉得到。
使用 Context ForEach 重载
首先说明“使用 Context”重载所带来的区别。
在下面这个普通重载中,你只能获取 name 和 value 两个属性。
ForEach(Expression<Action<string, object>> foreachAction)
这也是最基本的重载形式,可以让你读取所有属性的名称和值。
但是你可能还需要更多的上下文信息,因此就引入了一个可以使用 Context 进行访问的重载形式:
ForEach(Expression<Action<IObjectVisitorContext<T, object>>> foreachAction)
这就带来了一些优势:
- 你可以访问除了 Name 和 Value 之外更多的信息了,目前至少包括:表示原始访问对象的 SourceObject 和表示属性信息的 PropertyInfo
- Context 不是完全只读的。其中的 Value 属性允许赋值。因此,你可以通过赋值来修改原始对象中的属性值。这是通过参数传递无法做到的(未使用 ref)。
- 方法签名不会发生变化,因为只有一个参数。不会因为增加属性而需要修改方法签名。
不过这也会带来一些损失:
- 方法签名更长
- 运行时会创建 Context 对象,这将带来十分轻微的性能开销
因此,如果在你的场景中以上优势大于其损失,不妨也考虑使用 Context 。