寻求一种优雅的方式让继承的类具有" StateName"属性

时间:2014-08-11 20:15:39

标签: c# class inheritance macros types

请参阅下面的解决方案 - 搜索更新。

我有一个广泛的状态机架构,我通过为每个状态创建一个类来实现(有多个机器,但所有状态都从相同的'MachineState'类继承)。每个州都有一个静态属性“StateName”:

public class SomeState: MachineState
{

  // THIS BLOCK SHOULD BE COPIED TO ALL STATE CLASSES!!
  private static string _StateName;
  public static string StateName
  { 
     get {
           if (_StateName == null)
           { 
               _StateName = MethodBase
                  .GetCurrentMethod()
                  .DeclaringType
                  .ToString()
                  .Split(new char[] { '.' })
                  .ToList()
                  .Last();
           }
           return _StateName; 
          }  
  }
  // END OF BLOCK


  public SomeState(Queue<string> messages)  // 
        : base(messages)
  {
       ...
  }
...
}

呃。

至少我会调用处理器密集型的东西,每个级别只能获得一次名称 - 就我的目的而言,这是可接受的成本。但我真的想找到一些方法让他们“继承”这段代码 - 或者至少某种方式让他们把它包含在像宏的东西中。我有一个抽象属性,所以如果它没有实现,我会在编译时捕获它;但是,仍然必须有一种方法可以避免将这些混乱复制到每个类中 - 然后在需要时在每个类中更改它。

有什么想法吗?

感谢。

------------ UPDATE ---------------------------------- -----

生活充满妥协;这个我可以忍受的。 @Tallek在基类中提出了这个建议:

 public static string GetStateName<T>() where T : MachineState
    {
        return typeof(T).Name;
    }

我将它与我的静态属性集成在一起,就像这样(对于'SomeState'类):

    // THIS BLOCK SHOULD BE COPIED TO ALL STATE CLASSES!!
    public static string StateName { get { return GetStateName<SomeState>(); } }

不完美;我必须确保在每个类的GetStateName调用中获取正确的状态名称。但它做了两件我急于做的事情:它将逻辑移动到一个位置,并且更容易阅读。保持StateName抽象将帮助我捕获任何未实现StateName的状态。

再次感谢所有人。

4 个答案:

答案 0 :(得分:1)

  • 你有一个州
  • 你的州是班级
  • 您想将该状态与另一个
  • 进行比较
  • 您不想实现状态以进行比较

我不认为你这样做比:

更容易
if(state.GetType() == typeof(SomeState))

答案 1 :(得分:1)

我可能同意CodeCaster。枚举的20或30个州并不大。

根据您收到邮件的说明并确定该邮件的处理程序,并结合查看您的示例:

if(stateName == SomeState.StateName) { }

这意味着您有stateName作为参数。因此,每个州都有一个if块,以便您可以确定该消息适用于哪一个?

if(stateName == SomeState.StateName) { 

}
if(stateName == OtherState.StateName) { 

}

如果是这种情况......  (如果给出有限的用例信息,则该答案的其余部分基于该前提,因此如果其余部分不适用,请不要激怒我)

您希望所有类自动拥有此StateName属性。这看起来很糟糕,但是后来我们发现你仍然需要为每个状态设置一个if块,因为那个IMO的代码更多,所以干扰更少。你已经换了DRY换另一个DRY。

我会有枚举,每个都有

public enum States {
...
[Handler(typeof(SomeState))]
SomeState = 5,
...

结合工厂模式,现在你扔掉所有的if块,只需要打电话给你的工厂:

MachineState newState = StateFactory.Create(stateName);

工厂使用Enum.Parse将stateName转换为枚举,从中访问该属性以获取实例化所需的类型。 没有开关/案例/ if / else需要。

这意味着每次实现新的状态类时,只需要触摸一个地方,这就是枚举,并且代码重复次数最少。

如果每个if块在该特定状态中具有特定逻辑 将该代码移动到MachineState或IMachineState接口中定义的HandleMessage方法中,该接口具有每个SomeState的实现,以执行特定于该状态的内容。让我们假设您的消息指示州名称,也许还有一些&#34;内容&#34;或&#34;数据&#34;在需要处理的消息中:

MachineState newState = StateFactory.Create(stateName);
newState.HandleMessage(messageContent);

我意识到它可能比那更复杂。您可能需要将状态从状态处理分离到单独的类中以使其工作正常。很难说。如果我在你的鞋子里,我肯定会仔细考虑这个问题。

答案 2 :(得分:0)

它不是很好,但也许值得考虑......

public class MachineState
{
   public static string GetStateName<T>() where T : MachineState
   {
       return typeof(T).Name;
   }

}

像这样使用:

if("MyState" == MachineState.GetStateName<MyState>()) { ... }

答案 3 :(得分:0)

您可以使用扩展方法完成此操作:

public static string GetStateName(this MachineState state) {

  return state.GetType().Name;

}

像这样使用:

if(state.GetStateName() == "SomeState") { /* Do something */ }

如果你愿意,可以自己进行缓存:你可以访问你想要的任何静态结构。