Godot C#:能否将泛型类型用作信号参数?
问题
为了避免重复编写变量变化时发射信号的样板代码,我封装了一个泛型辅助类NotifyOnChange<[MustBeVariant]T>,但遇到了信号类型的问题:
最初的单个变量实现(以int为例):
[Signal] public delegate void ValueChangedEventHandler(int newValue); private int _value; public int Value { get => _value; set { _value = value; EmitSignal(SignalName.ValueChanged, Value); } }
泛型辅助类的实现:
using Godot; public partial class NotifyOnChange<[MustBeVariant]T> : RefCounted { [Signal] public delegate void ChangedEventHandler(Variant newValue); private T _value; public T Value { get => _value; set { _value = value; EmitSignal(SignalName.Changed, Variant.From(Value)); } } public NotifyOnChange() { } public NotifyOnChange(T value) { Value = value; } }
这个类能正常工作,但信号参数只能用Variant类型,订阅时需要手动转换类型,比较麻烦。我尝试把信号声明改成用泛型类型T:
[Signal] public delegate void ChangedEventHandler(T newValue);
但这样Godot不会生成信号后端,完全无法正常工作。我已经给泛型参数T加了[MustBeVariant]属性,想知道是操作有误还是Godot目前不支持这个功能?
解答
当前Godot的C#绑定暂不支持泛型类型作为信号参数,哪怕已经添加了[MustBeVariant]属性也不行。这是因为Godot的信号系统底层依赖于静态类型信息,泛型类型在编译时无法被Godot的信号生成器正确解析,导致无法生成对应的信号后端代码。
如果想避免手动转换Variant的麻烦,可以考虑以下两种替代方案:
- 为常用类型创建非泛型子类:比如针对
int、string、float等常用类型,分别继承NotifyOnChange<T>并重新声明对应类型的信号,这样订阅时就能直接使用强类型参数。示例:
public partial class NotifyInt : NotifyOnChange<int> { [Signal] public delegate void ChangedEventHandler(int newValue); public NotifyInt() : base() { } public NotifyInt(int value) : base(value) { } // 重写Value属性,发射强类型信号 public new int Value { get => base.Value; set { base.Value = value; EmitSignal(SignalName.Changed, value); } } }
- 使用事件而非Godot信号:如果不需要和Godot引擎的节点信号系统交互,可以直接用C#的原生事件,这样就能完美支持泛型类型:
using Godot; public partial class NotifyOnChange<[MustBeVariant]T> : RefCounted { public event Action<T> Changed; private T _value; public T Value { get => _value; set { _value = value; Changed?.Invoke(value); } } public NotifyOnChange() { } public NotifyOnChange(T value) { Value = value; } }
内容的提问来源于stack exchange,提问作者MeSteve95
相关产品推荐
相关产品推荐

