You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 22:40:57