A simple state machine using the Static class in C # to notify other subscribers through events

I am 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 that I have almost none, but I have a small problem, and I'm not sure how to work.

Here is 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 encountered is related to this line:

  OnStateChange(this, sysInfo); 

In particular, the word "this" is illegal. And I understand why: "this" should reference the self of the instance object (and not the static class).

I would prefer the Static class for my state machine, rather than one instance of multiple instances. (Not that it was so bad, but I feel like it makes the code cleaner a static class.)

So how should I work?

Update:

As a continuation, I chose Jon Skeet as the right one, because the problem was more about what approach I took, rather than the technical failure that I had. Although, almost all the other answers below determine the technical malfunction I was dealing with.

Oddly enough, as I examined the application that I wrote with my colleague, she indicated that the program should probably monitor the status of the connection to the server, as well as the status of the work being performed. (Yes, Virginia, that means I need two state machines ... Ergo, removing all the β€œstatic” keywords from the code above and making it a regular class is a smart approach.)

Thanks again everyone!

+4
source share
5 answers

Why do you need a static class? This is a finite state machine β€” it has a state β€” naturally proposes to use a non-static class. You can always have a static variable per instance, if you really want to.

Basically, your instinct is incorrect in my view - a regular class will make the code cleaner than static. Static classes should very rarely have any state at all - perhaps a cache (although this is dubious), or counters for diagnostic purposes, etc. Try to think in terms of objects, not classes. Does it make sense to have two separate state machines with a different current state and, possibly, with different event handlers? It is easy to imagine that the case - and this means that it is easy to create new instances for tests, etc. (It also allows independent testing in parallel). Therefore, the state in the machine instance is natural.

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

+14
source

You cannot use "this" when working in a static scope, such as a static class or a static method.

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

Alternatively, you might want to make your singleton state identifier. This will allow you to have one instance of a non-static class. This has one advantage, simplifying the transition to a non-static implementation if future changes also change.


In addition, you really need to check if there are any subscribers before the start of this event. Unable to 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); } } 
+6
source

Change the delegate:

from

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

in

 public static delegate void StateChangeHandler(SysInfoEventArgs sysStateInfo); 
+1
source

I would change this code:

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

in

 public static event Action<SysInfoEventArgs> OnStateChange; 
+1
source

If you really want to keep the static class and use the semantics of object sender , then the correct thing for the transition would be typeof(Sys) . It is also a similar (old and rare) idiom lock on a static class.

But this is just pedantic, because the event handler will never use this value, and in practice null will work just as well.

+1
source

Source: https://habr.com/ru/post/1303591/


All Articles