在这种情况下(C#)更换开关组和Enum的正确方法是什么?

XBi*_*13X 5 c# xna enums switch-statement

如果它有帮助,下面的问题是在我正在建立的游戏的背景下.

在几个不同的地方我有以下场景.存在一个父类,对于这个名为Skill的示例,我有许多子类来实现父类中的方法.还存在另一个我们称之为Vocation的父类.技能需要列在职业的不同子类中.但是,这些技能需要适用于使用任何给定职业的游戏中的任何内容.

我当前的设置是有一个名为Skill.Id的Enum,因此Vocation包含来自该Enum的值的集合,当游戏中的实体接受该Vocation时,该集合将被传递到另一个名为SkillFactory的类中.每次我创建一个新的Skill子类时,Skill.Id都需要一个新的条目,以及新子类的构造函数的switch块中的一个案例.

即:

//Skill.Id
Enum{FireSkill,WaterSkill,etc}

//SkillFactory
public static Skill Create(Skill.Id id)
{
    switch(id)
    {
        case Skill.Id.FireSkill:
             return new FireSkill();
        //etc
    }
}
Run Code Online (Sandbox Code Playgroud)

这非常好用,但是使用枚举和切换块作为一种介于两者之间的感觉就像解决这个问题所需的开销一样.是否有更优雅的方法来创建这些Skill子类的实例,但仍然允许Vocation包含一个集合来识别它可以使用的技能?

编辑:我很好地抛出枚举和关联的开关块,只要Vocation可以包含允许任意实例化Skill子类的集合.

Ree*_*sey 8

您可以创建Dictionary<Skill.Id, Func<Skill>>并使用它来实例化.

在构造函数中:

Dictionary<Skill.Id, Func<Skill>> creationMethods = new Dictionary<Skill.Id, Func<Skill>>();
public SkillFactory()
{
     creationMethods.Add(Skill.Id.FireSkill, () => new FireSkill());
     creationMethods.Add(Skill.Id.WaterSkill, () => new WaterSkill());
}
Run Code Online (Sandbox Code Playgroud)

然后,您的Create方法变为:

public static Skill Create(Skill.Id id)
{
     return creationMethods[id]();
}
Run Code Online (Sandbox Code Playgroud)

当然,这并不是更好 - 除了它允许您将其扩展到每个ID的其他功能,而不需要复制交换机块(如果需要).(只需将更多内容放入词典的值侧.)

话虽如此,从长远来看,完全摆脱枚举对于可扩展性来说是一个很好的好处.然而,这需要更精细的改变.例如,如果您使用MEF,则可以SkillFactory在运行时导入一组类型,并通过单个将它们与名称(通过元数据)相关联ImportMany.这将允许您在不更改工厂的情况下添加新的Skill子类,并通过名称或其他机制引用它们.