C#中IS与AS的适用场景?如何重构规避IS的效果触发代码?
C#中
is与as关键字的适用场景 is关键字
- 用于类型检查:判断对象是否属于指定类型(或其派生类型),返回布尔值。
- 典型适用场景:
- 仅需确认类型,无需后续转换的简单分支判断。
- C# 7.0+ 配合模式匹配,直接在检查时完成变量声明与转换,比如
if (effect is GeneralEffect generalEff),避免重复的类型校验和强制转换。 - 快速检查对象是否非空:
obj is not null。
as关键字
- 用于安全类型转换:尝试将对象转为指定类型,转换失败时返回
null(不会抛出InvalidCastException)。 - 典型适用场景:
- 需要转换类型且希望避免异常的场景,比如
var generalEff = effect as GeneralEffect; if (generalEff != null)。 - 仅支持引用类型或可空值类型,值类型无法使用
as转换。
- 需要转换类型且希望避免异常的场景,比如
规避
is类型判断的重构方案 你当前的问题核心是派生类Trigger方法签名不一致,导致必须通过类型判断来调用对应方法。以下是几种可行的重构思路:
方案1:统一Trigger方法签名,利用多态
修改抽象类BaseEffect,定义通用的Trigger方法,派生类根据自身逻辑处理参数:
public abstract class BaseEffect { public abstract void Trigger(EffectTriggerParams param); } // 通用参数容器,按需扩展字段 public class EffectTriggerParams { public Player Player { get; set; } public GeneralData GeneralData { get; set; } } public class GeneralEffect : BaseEffect { public override void Trigger(EffectTriggerParams param) { // 使用param.GeneralData执行原有逻辑 } } public class PlayerEffect : BaseEffect { public override void Trigger(EffectTriggerParams param) { // 使用param.Player执行原有逻辑 } } // 调用时直接遍历,无需类型判断 public class TestClass { public void TriggerAllEffects(List<BaseEffect> effects, EffectTriggerParams param) { foreach (var effect in effects) { effect.Trigger(param); } } }
方案2:使用访问者模式
如果无法统一Trigger方法签名,可通过访问者模式将类型判断逻辑转移到专门的访问者类中:
public abstract class BaseEffect { public abstract void Accept(IEffectVisitor visitor); } public interface IEffectVisitor { void Visit(GeneralEffect effect); void Visit(PlayerEffect effect); } public class GeneralEffect : BaseEffect { public void Trigger(GeneralData data) { // 原有逻辑 } public override void Accept(IEffectVisitor visitor) { visitor.Visit(this); } } public class PlayerEffect : BaseEffect { public void Trigger(Player player) { // 原有逻辑 } public override void Accept(IEffectVisitor visitor) { visitor.Visit(this); } } // 实现访问者,处理不同类型的Trigger调用 public class EffectTriggerVisitor : IEffectVisitor { private readonly Player _player; private readonly GeneralData _generalData; public EffectTriggerVisitor(Player player, GeneralData generalData) { _player = player; _generalData = generalData; } public void Visit(GeneralEffect effect) { effect.Trigger(_generalData); } public void Visit(PlayerEffect effect) { effect.Trigger(_player); } } // 调用代码 public class TestClass { public void TriggerAllEffects(List<BaseEffect> effects, Player player, GeneralData generalData) { var visitor = new EffectTriggerVisitor(player, generalData); foreach (var effect in effects) { effect.Accept(visitor); } } }
方案3:动态类型(临时场景适用)
如果是快速迭代的小型项目,可使用dynamic绕过编译时类型检查,但需注意运行时可能抛出异常:
public class TestClass { public void TriggerAllEffects(List<BaseEffect> effects, Player player, GeneralData generalData) { foreach (dynamic effect in effects) { if (effect is GeneralEffect) effect.Trigger(generalData); else if (effect is PlayerEffect) effect.Trigger(player); // 新增派生类时需补充判断,否则会触发运行时异常 } } }
内容的提问来源于stack exchange,提问作者Courier
相关产品推荐
相关产品推荐

