4

我一直在尝试为我的应用程序编写一个简单的静态类状态机,以便在系统状态更改时通知其他控件和代码。而且我想我几乎拥有它,但是我遇到了一个小问题,我不确定如何解决。

这是代码:

// An enum denoting the 3 States
public enum Status { Error = -1, Working, Ready }

// The main state change class
public static class Sys
{
    // system status
    private static Status state;

    // delegate and event
    public static delegate void StateChangeHandler(object sys, SysInfoEventArgs sysStateInfo);
    public static event StateChangeHandler OnStateChange;

    public static Status State
    {
        get { return state; }
        set
        {
            SysInfoEventArgs sysInfo = new SysInfoEventArgs(state, value);
            state = value;
            OnStateChange(this, sysInfo);
        }
    }
}

/// <summary>Contains previous and current state info</summary>
public class SysInfoEventArgs : EventArgs
{
    public readonly Status oldState;
    public readonly Status newState;
    public SysInfoEventArgs(Status oldState, Status newState)
    {
        this.oldState = oldState;
        this.newState = newState;
    }
}

我遇到的问题是这条线:

 OnStateChange(this, sysInfo);

具体来说,“this”这个词是非法的。我明白为什么:“this”应该指回实例化对象(而不是静态类)的自身。

我宁愿为我的状态机使用一个静态类,而不是我可以实例化多个副本的静态类。(并不是说这会是一件坏事,但我觉得它使代码更干净,有一个静态类。)

那么我该怎么做呢?

更新:

作为后续行动,我选择 Jon Skeet 的答案作为正确答案,因为问题更多是关于我所采用的方法,而不是我遇到的技术故障。虽然,下面几乎所有其他答案都解决了我正在处理的技术故障。

奇怪的是,当我和我的同事审查我编写的应用程序时,她指出该程序可能应该跟踪服务器连接的状态以及正在完成的工作的状态。(是的,Virginia,这意味着我需要 2 个状态机……所以,从上面的代码中删除所有“静态”关键字并使其成为常规类是明智的方法。)

再次感谢大家!

4

5 回答 5

14

为什么你想要一个静态类?它是一个状态机——它有状态——自然建议使用非静态类。如果你真的想的话,你总是可以有一个静态变量来引用它的单个实例。

基本上,在我看来,你的直觉是不正确的——拥有一个普通的类会使代码比静态的更干净。静态类应该很少有任何状态——也许是缓存(尽管这很可疑),或者用于诊断目的的计数器等。试着从对象而不是的角度来思考。拥有两个独立的状态机,具有不同的当前状态和可能不同的事件处理程序是否有意义?很容易想象这种情况——这意味着为测试等创建新实例很容易。(它还允许独立测试并行运行。)因此,在机器实例中拥有状态是很自然的。

有些人认为不应该有静态方法、静态类等。我认为这有点过分了,但你至少应该考虑引入静态的可测试性影响。

于 2010-03-09T19:16:11.190 回答
6

在静态范围内工作时不能使用“this”,例如静态类或静态方法。

您在这里有两个选择。您可以传递null“sys”参数。真的,这个参数,在静态类的情况下,真的没有用,因为“发送者”总是静态类。

或者,您可能需要考虑将您的状态通知程序设置为singleton。这将允许您拥有非静态类的单个实例。如果未来的需求也发生变化,这确实有一个优势,那就是更容易过渡到非静态实现。


此外,您确实应该在引发此事件之前检查以确保有订阅者。不这样做可能会导致问题:

public static Status State
{
    get { return state; }
    set
    {
        SysInfoEventArgs sysInfo = new SysInfoEventArgs(state, value);
        state = value;
        var handler = OnStateChange;
        if (handler != null)
            handler(null, sysInfo);
    }
}
于 2010-03-09T19:15:00.490 回答
1

修改您的委托:

从:

public static delegate void StateChangeHandler(object sys, SysInfoEventArgs sysStateInfo);

到:

public static delegate void StateChangeHandler(SysInfoEventArgs sysStateInfo);
于 2010-03-09T19:16:36.353 回答
1

我会更改此代码:

public static delegate void StateChangeHandler(object sys, SysInfoEventArgs sysStateInfo);
public static event StateChangeHandler OnStateChange;

到:

public static event Action<SysInfoEventArgs> OnStateChange;
于 2010-03-09T19:20:53.570 回答
1

如果您真的想保留静态类并使用 的语义object sender,那么正确传递的就是typeof(Sys). 这也类似于静态类上的(旧的和罕见的)锁定习惯用法。

但这只是迂腐,因为事件处理程序永远不会使用该值,并且在实践中null也可以正常工作。

于 2010-03-09T19:27:17.297 回答