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

子类能否重写父类属性并更改其泛型类型?Unity开发求助

解决方案

你遇到的问题是C#中重写属性时返回类型必须兼容,直接在子类中用泛型接口重写基类的非泛型接口属性是不允许的。这里提供两种可行的解决思路:

思路一:使用泛型基类

将基类改为泛型抽象类,让每个子类继承时指定自身类型,这样可以在基类中直接定义带泛型约束的Preset属性,子类重写时自然匹配类型:

// 泛型基类,约束T为自身类型的控制器
public abstract class CharacterMovementController<T> : MonoBehaviour where T : CharacterMovementController<T>
{
    public abstract IStatePreset<T> Preset { get; protected set; }
}

// X轴控制器,继承时指定自身类型
public class CharacterXMovementController : CharacterMovementController<CharacterXMovementController>
{
    public override IStatePreset<CharacterXMovementController> Preset { get; protected set; }
}

// Z轴控制器同理
public class CharacterZMovementController : CharacterMovementController<CharacterZMovementController>
{
    public override IStatePreset<CharacterZMovementController> Preset { get; protected set; }
}

// Y轴控制器同理
public class CharacterYMovementController : CharacterMovementController<CharacterYMovementController>
{
    public override IStatePreset<CharacterYMovementController> Preset { get; protected set; }
}

这种方式的优势是类型安全直接由泛型约束保证,无需额外类型转换,代码结构清晰。

思路二:保留非泛型基类,结合协变接口与显式实现

如果不想修改基类的非泛型结构,可以通过定义协变泛型接口,再用显式接口实现来兼容基类的属性:

第一步:调整接口定义,添加协变

// 非泛型基接口,作为泛型接口的父接口
public interface IStatePreset { }

// 泛型接口添加协变标记(out T),允许子类接口赋值给父接口
public interface IStatePreset<out T> : IStatePreset where T : CharacterMovementController { }

第二步:子类实现显式接口+隐藏属性

每个子类定义自己的泛型Preset属性,同时显式实现基类的非泛型属性,将其指向子类的泛型属性:

public abstract class CharacterMovementController : MonoBehaviour
{
    public abstract IStatePreset Preset { get; protected set; }
}

public class CharacterXMovementController : CharacterMovementController
{
    // 子类专属的泛型Preset属性
    public new IStatePreset<CharacterXMovementController> Preset { get; protected set; }

    // 显式实现基类的Preset属性,进行类型转换
    public override IStatePreset CharacterMovementController.Preset
    {
        get => Preset;
        protected set => Preset = value as IStatePreset<CharacterXMovementController>;
    }
}

// Z轴控制器实现
public class CharacterZMovementController : CharacterMovementController
{
    public new IStatePreset<CharacterZMovementController> Preset { get; protected set; }

    public override IStatePreset CharacterMovementController.Preset
    {
        get => Preset;
        protected set => Preset = value as IStatePreset<CharacterZMovementController>;
    }
}

// Y轴控制器实现
public class CharacterYMovementController : CharacterMovementController
{
    public new IStatePreset<CharacterYMovementController> Preset { get; protected set; }

    public override IStatePreset CharacterMovementController.Preset
    {
        get => Preset;
        protected set => Preset = value as IStatePreset<CharacterYMovementController>;
    }
}

这种方式保留了原有的非泛型基类结构,同时子类可以拥有类型安全的泛型Preset属性。需要注意的是,赋值时如果类型不匹配,as转换会返回null,可以根据需求添加类型检查逻辑。

你的预设类写法可以保持不变,比如PresetA实现多个泛型接口的方式依然有效:

public class PresetA : ScriptableObject, IStatePreset<CharacterXMovementController>, IStatePreset<CharacterZMovementController> {}

内容的提问来源于stack exchange,提问作者Fraspo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:53:09