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

C#调用继承类Visit方法时执行父类实现而非子类重载问题求解

问题原因

C#的方法重载决议发生在编译阶段,只会根据参数的编译时类型匹配对应的重载,不会参考运行时的实际类型。
你代码中Collide方法的ent1参数编译时类型是Entity,因此编译器会固定匹配参数为Entity的Visit重载,哪怕运行时ent1的实际类型是Player,也不会自动切换到Visit(Player)的重载,这就是为什么实际执行到了基类的Visit(Entity)方法。

修复方案

提供两种通用可扩展方案,新增实体类型时不需要修改现有逻辑:

方案1:使用dynamic延迟重载决议(实现最简单)

只需修改Collide方法的调用逻辑,将ent1强转为dynamic,即可让重载决议推迟到运行时,自动匹配ent1实际类型对应的Visit重载:

public virtual void Collide(Entity ent1, Entity ent2)
{
    ent2.Visit((dynamic)ent1);
}

该方案优势是改动极小,劣势是没有编译时类型检查,如果某个实体类型没有对应的Visit重载,会在运行时报错。

方案2:标准访问者模式实现(类型安全,推荐)

在基类中新增Accept抽象方法,每个子类实现该方法时传递自身的具体类型给Visit调用,从语法层面保证重载匹配正确:

  1. 首先修改Entity基类:
public abstract class Entity
{
    public virtual void Visit(Enemy enemy) { }
    public virtual void Visit(Player enemy) { }
    public virtual void Visit(Entity enemy) { }
    
    // 新增Accept抽象方法
    public abstract void Accept(Entity visitor);
    
    public virtual void Collide(Entity ent1, Entity ent2)
    {
        // 改为调用Accept方法
        ent1.Accept(ent2);
    }
}
  1. 每个实体子类实现Accept方法:
public class Enemy : Entity
{
    public override void Visit(Enemy enemy) { }
    public override void Visit(Player enemy) { }
    
    // this的编译时类型为Enemy,会自动匹配Visit(Enemy)重载
    public override void Accept(Entity visitor)
    {
        visitor.Visit(this);
    }
}

public class Player : Entity
{
    public override void Visit(Enemy enemy) { }
    public override void Visit(Player enemy) { }
    
    // this的编译时类型为Player,会自动匹配Visit(Player)重载
    public override void Accept(Entity visitor)
    {
        visitor.Visit(this);
    }
}

该方案优势是所有重载匹配都有编译时检查,新增实体类型时只需在基类加对应的Visit重载、新子类实现Accept即可,不会出现运行时类型错误,适合实体类型较多的生产项目。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 18:27:01