GObject调用get_property获取gchararray类型属性报错咨询
问题解答
一、运行抛出GValue类型错误的原因与修复
代码存在两处核心错误:
- GValue初始化方式不符合GJS绑定规范
GJS对GObject.Value做了封装,不支持new创建空对象后手动调用init()初始化:这种写法会导致GJS绑定层无法正确识别GValue的已初始化状态,底层C API拿到的是类型标记为空的通用GValue,和声明的TYPE_STRING不匹配,因此抛出类型错误。
正确的GValue初始化应该直接在构造函数传入类型和初始值:
实际上在GJS中不需要手动构造GValue,// 正确初始化方式,不需要单独调用init() const GValue_RV = new GOBJECT.Value(GOBJECT.TYPE_STRING, '');get_property会自动做类型转换返回对应JS类型的值,直接接收返回值即可:const propValue = go_Obj.get_property("example-property-c"); log(propValue); // 直接拿到字符串值 example-property-c被自定义JS属性遮蔽
你在_init方法中调用super._init(properties)之前,就执行了this.example_property_c = null。此时GObject实例的内部属性存储还未完成初始化,这行赋值不会走到GObject自动生成的属性setter逻辑,反而会直接在JS实例对象上创建一个同名自有属性,后续所有对this.example_property_c的读写都会直接操作这个自有JS属性,完全绕过GObject的属性系统,导致set_property/get_property操作的内部存储和JS属性访问的不是同一个值。
修复方式是调整初始化顺序,私有变量提前初始化,GObject属性赋值放在super._init()之后执行:_init (properties) { // 自定义getter/setter对应的内部私有变量,可以在super前初始化 this._example_property_a = 0; this._example_property_b = true; // 先完成GObject实例初始化,挂载自动生成的属性访问器、初始化内部属性存储 super._init(properties); // 再给GObject属性赋值 this.example_property_c = null; }
你实现的example-property-a和example-property-b的notify逻辑是正确的:前者判断值实际变更后才触发notify,后者只要执行赋值就触发notify,符合GObject的常规实现规范。
二、是否支持实例级安装ParamSpec属性
不支持。GObject的属性系统是类级别的设计:所有ParamSpec(属性定义)都存储在类的结构体中,同一个类的所有实例共享同一套属性定义,没有提供给单个实例动态安装新属性的API。
如果需要给单个实例挂载动态数据,可以选择替代方案:
- 不需要类型校验、notify信号的场景:直接用GObject内置的data存储接口,调用
instance.set_data("key", value)存值,instance.get_data("key")取值。 - 需要类型校验、notify信号的场景:要么在类注册时预先定义好所有可能用到的属性,要么通过动态类型注册机制为需要额外属性的实例单独创建临时子类,本质还是类级别的属性定义。
内容的提问来源于stack exchange,提问作者Schmaehgrunza
相关产品推荐
相关产品推荐

