我有一个广泛的状态机架构,我通过为每个状态创建一个类来实现(有多个机器,但所有状态都从相同的'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的状态。
再次感谢所有人。
答案 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 */ }
如果你愿意,可以自己进行缓存:你可以访问你想要的任何静态结构。