Простая машина состояния, использующая class Static в C # для уведомления других подписчиков через события

Я пытаюсь написать простую машину состояний статического classа для моего приложения, чтобы уведомлять другие элементы управления и код при изменении состояния системы. И я думаю, что у меня его почти нет, но у меня возникает небольшая проблема, и я не уверен, как работать.

Вот код:

// 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); } } } /// Contains previous and current state info 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); 

В частности, слово «это» является незаконным. И я понимаю, почему: «это», как предполагается, относится к самости экземпляра объекта (а не статического classа).

Я предпочел бы иметь статический class для моего конечного автомата, а не тот, который я могу создать несколько копий. (Не то, чтобы это было так плохо, но я чувствую, что он делает очиститель кода статическим classом.)

Итак, как я должен работать?

Обновить:

В качестве продолжения я выбрал ответ Джона Скита как правильный, потому что проблема была скорее в том, какой подход я принимал, а не в техническом провале, который у меня был. Хотя, почти все остальные ответы ниже определяют технический сбой, с которым я имел дело.

Как ни странно, по мере того как я рассматривал с моим коллегой приложение, которое я написал, она указала, что программа должна, вероятно, отслеживать состояние соединения с сервером, а также состояние выполняемой работы. (Да, Вирджиния, это означает, что мне нужны 2 государственные машины … Ergo, удалить все «статические» ключевые слова из кода выше и сделать его обычным classом – это умный подход.)

Еще раз спасибо, всем!

Зачем вам нужен статический class? Это конечный автомат – он имеет состояние – естественно предлагает использовать нестатический class. У вас всегда может быть статическая переменная, относящаяся к одному экземпляру, если вы действительно этого хотите.

В принципе, ваш инстинкт неверен в моем представлении – обычный class сделает код более чистым, чем статический. Статические classы должны очень редко иметь какое-либо состояние вообще – возможно, кеш (хотя и это сомнительно), или счетчики для диагностических целей и т. Д. Попытайтесь думать в терминах объектов, а не classов . Имеет ли смысл иметь две отдельные машины состояний с другим текущим состоянием и, возможно, с различными обработчиками событий? Легко представить, что это так, и это означает, что легко создавать новые экземпляры для тестов и т. Д. (Он также позволяет проводить независимые тесты параллельно). Следовательно, состояние в экземпляре машины является естественным.

Есть люди, которые считают, что не должно быть статических методов, нет статических classов и т. Д. Я думаю, что это немного далеко, но вы всегда должны, по крайней мере, учитывать влияние тестируемости внедрения статики.

Вы не можете использовать «это», когда работаете в статической области, например статический class или статический метод.

У вас есть два варианта. Вы можете передать значение null для параметра «sys». Действительно, этот параметр в случае статического classа действительно не полезен, поскольку «отправитель» всегда является статическим classом.

В качестве альтернативы, вы можете захотеть сделать свой штат оповещением о синглете . Это позволит вам иметь один экземпляр нестатического classа. У этого есть одно преимущество, упрощающее переход к нестатической реализации, если изменения в будущем также меняются.


Кроме того, вам действительно нужно проверить, есть ли абоненты до начала этого мероприятия. Невозможно вызвать проблемы:

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

Измените свой делегат:

от:

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

чтобы:

 public static delegate void StateChangeHandler(SysInfoEventArgs sysStateInfo); 

Я бы изменил этот код:

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

чтобы:

 public static event Action OnStateChange; 

Если вы действительно хотите сохранить статический class и использовать семантику object sender , то правильной передачей будет typeof(Sys) . Это также аналогично (старая и редкая) блокировка идиомы на статическом classе.

Но это просто педантично, потому что обработчик событий никогда не будет использовать эту ценность, и на практике null будет работать так же хорошо.