你可以使用C# 8.0中引入的
switch表达式和
模式匹配一起使用。
假设有以下声明:
public enum Gender
{
Other,
Female,
Male
}
public enum Age
{
Young,
Old
}
public enum MonsterType
{
Fire,
Ice,
Wood
}
class Monster
{
public Gender Gender { get; set; }
public Age Age { get; set; }
public MonsterType Type { get; set; }
}
使用元组模式:
return (monster.Gender, monster.Age, monster.Type) switch {
(Gender.Male, Age.Old, MonsterType.Ice) => 2,
(Gender.Male, Age.Old, MonsterType.Wood) => 6,
(Gender.Male, Age.Young, MonsterType.Ice) => 12,
... etc.
_ => -1
};
使用属性模式:
return monster switch {
{ Gender: Gender.Male, Age: Age.Old, Type: MonsterType.Ice } => 2,
{ Gender: Gender.Male, Age: Age.Old, Type: MonsterType.Wood } => 6,
{ Gender: Gender.Male, Age: Age.Young, Type: MonsterType.Ice } => 12,
... etc.
_ => -1
};
通过向
Monster
类添加
Deconstruct
方法,...
public void Deconstruct(out Gender gender, out Age age, out MonsterType type)
{
gender = Gender;
age = Age;
type = Type;
}
...我们可以使用位置模式(看起来像元组模式;但是,我们可以直接在monster
上进行切换,而不必先创建元组):
return monster switch {
(Gender.Male, Age.Old, MonsterType.Ice) => 2,
(Gender.Male, Age.Old, MonsterType.Wood) => 6,
(Gender.Male, Age.Young, MonsterType.Ice) => 12,
... etc.
_ => -1
};
如果我们将怪物声明为
记录,那么我们就可以免费获得这个Deconstruct方法:
record Monster (Gender Gender, Age Age, MonsterType Type);
一个更面向对象的方法是从抽象基类中派生出不同的怪物类,以代替拥有一个“Type”属性。这些怪物类将负责自己的“Result”值(无论这代表什么,我会保留名称“Result”)。
然后您只需要在“Gender”和“Age”上切换即可。
抽象基类(现在枚举“MonsterType”已过时):
abstract class Monster
{
public Gender Gender { get; set; }
public Age Age { get; set; }
public void Deconstruct(out Gender gender, out Age age)
{
gender = Gender;
age = Age;
}
public abstract int Result { get; }
}
一个针对Fire类型的实现
class FireMonster : Monster
{
public override int Result => this switch {
(Gender.Male, Age.Young) => 1,
(Gender.Female, Age.Young) => 4,
(Gender.Other, Age.Young) => 7,
_ => -1
};
}
注意:如果情况涵盖了性别和年龄的所有组合,即它们是穷尽的,则不再需要默认情况
_ =>
(如果这些属性属于枚举类型。如果它们是
int
常量,则C#编译器无法确定它们是否穷尽)。