Dart中如何判断getter是否被调用并区分调用场景
Dart中判断getter调用场景的实现方式
首先明确核心限制:Dart原生getter本身无法直接区分你提到的两种使用场景。
getter的执行逻辑只会在取值的瞬间触发,当getter把返回值交给调用方之后,调用方是直接丢弃返回值、还是调用返回值的成员方法,getter本身完全感知不到——这是语言层面的设计,没有内置API可以获取返回值的后续使用状态。
如果要实现场景区分,只能通过改造实现逻辑来达成,下面是两种可落地的方案:
方案1:返回代理包装类,拦截成员调用
不要直接返回原始的_value对象,而是返回一个代理对象,通过代理拦截所有对原始值的成员访问,以此判断是否在getter调用后有后续成员操作。
import 'dart:mirrors'; // 代理返回值的包装类 class ValueWrapper<T> { final T origin; bool _hasMemberCall = false; final void Function(bool isOnlyGet) onAccessFinish; ValueWrapper(this.origin, this.onAccessFinish); // 拦截所有对原始对象的成员访问、方法调用 @override dynamic noSuchMethod(Invocation inv) { _hasMemberCall = true; // 把调用转发给原始对象 return reflect(origin).delegate(inv); } // 同步任务执行完后检查访问状态 void checkStatus() { Future.microtask(() => onAccessFinish(!_hasMemberCall)); } } class MyClass<T> { MyClass(this._value); T _value; ValueWrapper<T> get value { print("Getter 被调用"); final wrapper = ValueWrapper<T>(_value, (isOnlyGet) { if (isOnlyGet) { print("场景1:仅访问getter完成取值,无后续操作"); } else { print("场景2:取值后调用了返回值的成员方法"); } }); wrapper.checkStatus(); return wrapper; } } // 测试代码 void main() { final myClass = MyClass([]); // 场景1:仅取值 myClass.value; // 场景2:取值后调用成员 // myClass.value.add(1); }
注意事项
dart:mirrors在Flutter等AOT编译环境下不可用,如果是这类场景,不需要用反射,针对你要返回的具体类型(比如示例中的List)手写对应的方法代理即可。- 该判断基于同步执行逻辑,如果调用方把getter返回值存到变量里,隔了几个异步周期再调用成员,会被判定为「仅取值」,和你给出的两个示例场景的判断逻辑一致。
方案2:拆分API,从设计上消除歧义
如果不想用代理类的拦截逻辑,最稳妥、兼容性最好的方式是拆分API,不要把两种场景的逻辑都塞到getter里:
- 保留基础getter,专门处理仅取值的场景
- 提供显式的操作方法,专门处理取值后需要调用成员的场景
class MyClass<T> { MyClass(this._value); T _value; // 仅取值场景调用 T get value { print("仅访问getter取值"); return _value; } // 需要操作返回值成员时调用 T withValue(void Function(T val) operator) { print("访问getter后操作成员"); operator(_value); return _value; } } // 使用示例 void main() { final myClass = MyClass([]); // 场景1:仅取值 final v = myClass.value; // 场景2:操作成员 myClass.withValue((list) => list.add(1)); }
这个方案没有任何魔法逻辑,全平台兼容、性能无损耗,只是需要调用方按照场景选择对应的API,无法做到自动拦截判断。
内容的提问来源于stack exchange,提问作者Mohammed CHAHBOUN
相关产品推荐
相关产品推荐

