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

C#通过父类ObjectA引用赋值ObjectB独有字段是否必须做类型检查

除了强制类型转换外,有3种更符合开闭原则、可维护性更强的实现方案:

方案1:接口抽象(最常用,性价比最高)

给所有需要接收time参数的类型定义公共接口,不需要修改原有父类ObjectA的逻辑,后续新增需要时间参数的子类只需实现接口即可,适配性极强。

// 定义公共接口
public interface ITimeSettable
{
    void SetTime(float time);
}

// 让ObjectB实现接口
public class ObjectB : ObjectA, ITimeSettable
{
    public float time;
    public void SetTime(float time) => this.time = time;
    public override void StuffToDo()
    {
        // 使用time的业务逻辑
    }
}

// 修改ObjectX的PassTimeToObjectB方法
public void PassTimeToObjectB()
{
    if (_objectAOrBStoredInAReference is ITimeSettable timeSettable)
    {
        timeSettable.SetTime(time);
    }
}

这种方案的判断逻辑没有和具体子类绑定,后续新增ObjectD等需要接收time的子类只要实现ITimeSettable即可,不需要修改ObjectX的现有代码。

方案2:访问者模式(适合类层次结构稳定的场景)

如果你当前的ObjectA子类数量已经固定,后续不会频繁新增子类,可以用访问者模式实现完全类型安全的操作分发,完全不需要任何运行时类型判断。

// 定义访问者接口
public interface IObjectAVisitor
{
    void Visit(ObjectB b);
    void Visit(ObjectC c); // 其他子类对应添加Visit方法
}

// 修改父类ObjectA,新增Accept方法
public abstract class ObjectA
{
    public abstract void StuffToDo();
    public abstract void Accept(IObjectAVisitor visitor);
}

// ObjectB实现Accept方法
public class ObjectB : ObjectA
{
    public float time;
    public void SetTime(float time) => this.time = time;
    public override void StuffToDo() { /* 业务逻辑 */ }
    public override void Accept(IObjectAVisitor visitor) => visitor.Visit(this);
}

// ObjectC实现Accept方法
public class ObjectC : ObjectA
{
    public override void StuffToDo() { /* 业务逻辑 */ }
    public override void Accept(IObjectAVisitor visitor) => visitor.Visit(this);
}

// 修改ObjectX,实现访问者接口
public class ObjectX : IObjectAVisitor
{
    public float time;
    private ObjectA _objectAOrBStoredInAReference;

    public ObjectX(ObjectA objectAOrB)
    {
        _objectAOrBStoredInAReference = objectAOrB;
    }

    public void PassTimeToObjectB()
    {
        _objectAOrBStoredInAReference.Accept(this);
    }

    public void SomeStuffToDo()
    {
        PassTimeToObjectB();
        _objectAOrBStoredInAReference.StuffToDo();
    }

    // 实现访问者接口的Visit方法
    void IObjectAVisitor.Visit(ObjectB b)
    {
        b.SetTime(time);
    }

    void IObjectAVisitor.Visit(ObjectC c)
    {
        // ObjectC不需要time,空实现即可
    }
}

这种方案所有类型校验都在编译期完成,不会出现运行时类型转换异常。

方案3:构造时注入委托(适合创建ObjectX时就明确传入对象类型的场景)

如果ObjectX实例创建的时候,你已经明确知道传入的是ObjectB还是其他子类,可以在构造阶段直接把设置time的逻辑注入,运行时完全不需要任何重复的类型校验。

public class ObjectX
{
    public float time;
    private ObjectA _objectAOrBStoredInAReference;
    private Action<float> _setTimeAction;

    public ObjectX(ObjectA objectAOrB)
    {
        _objectAOrBStoredInAReference = objectAOrB;
        // 构造时一次性判断,后续不用重复执行
        if (objectAOrB is ObjectB b)
        {
            _setTimeAction = t => b.SetTime(t);
        }
        // 其他子类有需要的也可以对应加逻辑
    }

    public void PassTimeToObjectB()
    {
        _setTimeAction?.Invoke(time);
    }

    // 其余代码保持不变
}

这种方案的类型判断只在构造时执行一次,后续调用PassTimeToObjectB的时候没有任何额外开销,性能最优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 04:48:03