针对类型转换式分支逻辑,有无更佳替代方案?能否用switch-case实现?
替代类型判断分支的方案及switch-case实现
首先,完全可以用switch-case实现该逻辑,C# 7.0及以上支持类型模式匹配的switch语句,能替代原有的if-else分支,代码更简洁易读:
public class Test{ public Animal DoSomething(AnimalCreateDto animal){ return animal switch { DogCreateDto dogDto => Create(new Dog(dogDto)), CatCreateDto catDto => Create(new Cat(catDto)), _ => throw new ArgumentException("不支持的AnimalCreateDto类型") }; } private Dog Create(Dog dog){ ... } private Cat Create(Cat cat){ ... } }
(注:原代码里的CateCreateDto应为笔误,修正为CatCreateDto)
除了switch-case,还有几种更优的方案可以彻底消除类型判断分支:
1. 多态模式(推荐,符合开闭原则)
让AnimalCreateDto定义抽象方法,子类负责将自身转换为对应的Animal实体,这样DoSomething无需任何类型判断:
// 定义抽象基类 public abstract class AnimalCreateDto { public abstract Animal ToAnimal(); } public class DogCreateDto : AnimalCreateDto { public override Animal ToAnimal() => new Dog(this); } public class CatCreateDto : AnimalCreateDto { public override Animal ToAnimal() => new Cat(this); } // Test类简化为: public class Test{ public Animal DoSomething(AnimalCreateDto animal){ var animalEntity = animal.ToAnimal(); return Create(animalEntity); } // 可统一为一个Create方法(逻辑允许的话),或保留重载 private Animal Create(Animal animal){ // 根据实际类型处理,若Create逻辑也能抽象到Animal子类,可彻底消除判断 if(animal is Dog dog) { ... } else if(animal is Cat cat) { ... } } }
如果Create的逻辑也能通过Animal子类的多态方法实现(比如animal.Save()),那连最后的类型判断也能消除,完全遵循开闭原则——新增动物类型时,只需新增Dto和Animal子类,无需修改Test类代码。
2. 类型映射字典
如果无法修改Dto结构,可用字典存储类型到处理逻辑的映射,避免硬编码分支:
public class Test{ private static readonly Dictionary<Type, Func<AnimalCreateDto, Animal>> _typeHandlers = new() { { typeof(DogCreateDto), dto => Create(new Dog((DogCreateDto)dto)) }, { typeof(CatCreateDto), dto => Create(new Cat((CatCreateDto)dto)) } }; public Animal DoSomething(AnimalCreateDto animal){ if(_typeHandlers.TryGetValue(animal.GetType(), out var handler)) { return handler(animal); } throw new ArgumentException("不支持的AnimalCreateDto类型"); } private Dog Create(Dog dog){ ... } private Cat Create(Cat cat){ ... } }
新增类型时,只需在字典中添加对应条目,无需修改DoSomething方法逻辑。
3. 访问者模式(适合复杂场景)
如果Dto结构复杂且无法修改,同时需要对不同类型Dto执行多种操作,访问者模式是合适的选择:
// 定义访问者接口 public interface IAnimalCreateDtoVisitor<T> { T Visit(DogCreateDto dto); T Visit(CatCreateDto dto); } // 让Dto接受访问者 public abstract class AnimalCreateDto { public abstract T Accept<T>(IAnimalCreateDtoVisitor<T> visitor); } public class DogCreateDto : AnimalCreateDto { public override T Accept<T>(IAnimalCreateDtoVisitor<T> visitor) => visitor.Visit(this); } public class CatCreateDto : AnimalCreateDto { public override T Accept<T>(IAnimalCreateDtoVisitor<T> visitor) => visitor.Visit(this); } // 实现创建Animal的访问者 public class AnimalCreationVisitor : IAnimalCreateDtoVisitor<Animal> { private readonly Test _test; public AnimalCreationVisitor(Test test) => _test = test; public Animal Visit(DogCreateDto dto) => _test.Create(new Dog(dto)); public Animal Visit(CatCreateDto dto) => _test.Create(new Cat(dto)); } // Test类使用访问者 public class Test{ public Animal DoSomething(AnimalCreateDto animal){ var visitor = new AnimalCreationVisitor(this); return animal.Accept(visitor); } private Dog Create(Dog dog){ ... } private Cat Create(Cat cat){ ... } }
这种方式适合需要对Dto执行多种不同操作的场景,新增类型时只需扩展访问者接口和实现类,以及Dto的Accept方法。
内容的提问来源于stack exchange,提问作者SNO
相关产品推荐
相关产品推荐

