使用 C# 中的静态类通过事件通知其他订阅者的简单状态机

发布于 2024-08-24 11:13:39 字数 1610 浏览 4 评论 0原文

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

这是代码:

// 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 个状态机...因此,从上面的代码中删除所有“静态”关键字并使其成为常规类是明智的方法。)

再次感谢大家!

I've been trying to write a simple Static-class State Machine for my application to notify other controls and code when the system state changes. And I think I almost have it, but I'm running into a small issue that I'm not sure how to work around.

Here's the code:

// 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;
    }
}

The problem I am having is with this line:

 OnStateChange(this, sysInfo);

Specifically, the word "this" is illegal. And I understand why: "this" is supposed to refer back to the self of an instantiated object (not a static class).

I would prefer to have a Static class for my state machine rather than one that I can instantiate multiple copies of. (Not that it would be such a bad thing, but I feel it makes the code cleaner having a static class.)

So how am I supposed to work this?

Update:

As a follow-up, I selected Jon Skeet's answer as the correct one because the issue was more about the approach I was taking, rather than a technical failure that I was having. Although, pretty much all of the other answers below fix the technical glitch I was dealing with.

Oddly enough, as I was reviewing with my co-worker the application that I wrote, she pointed out that the program should probably track both the state of the server connection as well as the state of the work being done. (Yes, Virginia, this means I need 2 state machines... Ergo, remove all the "static" keywords from the code above and make it a regular class was the smart approach.)

Thanks again, everyone!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

在风中等你 2024-08-31 11:13:39

为什么你想要一个静态类?它是一个状态机 - 它有状态 - 自然建议使用非静态类。如果您确实愿意,您始终可以有一个静态变量来引用它的单个实例。

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

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

Why would you want a static class? It's a state machine - it has state - that naturally suggests using a non-static class. You can always have a static variable referring to a single instance of it if you really want to.

Basically, your instinct is incorrect in my view - having a normal class would make the code cleaner than a static one. Static classes should very rarely have any state at all - perhaps a cache (although even that's dubious), or counters for diagnostic purposes etc. Try to think in terms of objects rather than classes. Does it make sense to have two separate state machines, with a different current state and perhaps different event handlers? It's easy to imagine that's the case - and it means it's easy to create new instances for tests etc. (It also allows independent tests to run in parallel.) Having the state in an instance of the machine is therefore a natural fit.

There are some people who believe there should be no static methods, no static classes etc. I think that's taking it a bit far, but you should always at least consider the testability impact of introducing statics.

甜`诱少女 2024-08-31 11:13:39

当您在静态范围(例如静态类或静态方法)中工作时,不能使用“this”。

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

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


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

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);
    }
}

You can't use "this" when you're working within a static scope, such as a static class or a static method.

You have two options here. You can pass null for the "sys" parameter. Really, this parameter, in the case of a static class, is really not useful, since the "sender" is always the static class.

Alternatively, you might want to consider making your state notifier a singleton. This would allow you to have a single instance of a non-static class. This does have the one advantage of making it easier to transition to a non-static implementation if future requirements change, as well.


In addition, you really should check to make sure there are subscribers prior to raising this event. Not doing so could cause problems:

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);
    }
}
归属感 2024-08-31 11:13:39

修改您的委托:

从:

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

到:

public static delegate void StateChangeHandler(SysInfoEventArgs sysStateInfo);

Modify your delegate:

from:

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

to:

public static delegate void StateChangeHandler(SysInfoEventArgs sysStateInfo);
听你说爱我 2024-08-31 11:13:39

我会将此代码更改

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

为:

public static event Action<SysInfoEventArgs> OnStateChange;

I'd change this code:

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

to:

public static event Action<SysInfoEventArgs> OnStateChange;
萌吟 2024-08-31 11:13:39

如果您确实想保留静态类并使用object sender 的语义,那么正确传递的内容是typeof(Sys)。这也类似于静态类上的(古老且罕见的)锁定习惯用法。

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

If you really want to keep the static class and use the semantics of object sender, then the proper thing to pass would be typeof(Sys). This is also analogous to the (old and rare) locking idiom on a static class.

But that's just being pedantic, because the event handler will never use that value, and in practice null would work just as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文