Uma simples máquina de Estado usando uma classe estática em C # para notificar outros assinantes através de eventos

StackOverflow https://stackoverflow.com/questions/2411803

Pergunta

Eu tenho tentando escrever um simples Static-classe máquina Estado para a minha candidatura para notificar outros controles e código quando o estado do sistema muda. E eu acho que quase tê-lo, mas eu estou correndo em um pequeno problema que eu não tenho certeza de como contornar.

Aqui está o código:

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

O problema que estou tendo é com esta linha:

 OnStateChange(this, sysInfo);

Especificamente, a palavra "este" é ilegal. E eu entendo o porquê: "isto" é suposto que remetem para o auto de um objeto instanciado (não uma classe estática)

.

Eu preferiria ter uma classe estática para a minha máquina de estado em vez de um que eu possa instanciar múltiplas cópias de. (Não que isso seria uma coisa tão ruim, mas eu sinto que torna o código mais limpo tendo uma classe estática.)

Então, como é que eu vou trabalhar isso?

Update:

Como um follow-up, selecionei a resposta de Jon Skeet como o correto, porque a questão era mais sobre a abordagem que eu estava tomando, ao invés de uma falha técnica que eu estava tendo. Embora, praticamente todas as outras respostas abaixo correção da falha técnica que eu estava lidando.

Curiosamente, como eu estava revendo com o meu colega de trabalho do aplicativo que eu escrevi, ela assinalou que o programa provavelmente deve acompanhar tanto o estado da conexão do servidor, bem como o estado do trabalho que está sendo feito. (Sim, Virginia, isso significa que eu preciso de 2 máquinas de estado ... Ergo, remova todas as palavras-chave "estática" do código acima e torná-lo uma classe regular foi a abordagem inteligente.)

Mais uma vez obrigado a todos!

Foi útil?

Solução

Por que você quer uma classe estática? É um Estado máquina - que tem Estado - que, naturalmente, sugere o uso de uma classe non-static. Você sempre pode ter uma variável estática referindo-se a uma única instância de que se você realmente quer.

Basicamente, seu instinto é incorreta na minha opinião - Tendo uma classe normal seria fazer o código mais limpo do que um estático. classes estáticas muito raramente deve ter qualquer estado em tudo - talvez um cache (embora mesmo que é duvidoso), ou contadores para fins de diagnóstico etc. Tente pensar em termos de objetos em vez de aulas . Faz sentido ter duas máquinas de estados separados, com um estado atual diferente e manipuladores de eventos talvez diferentes? É fácil imaginar que é o caso - e isso significa que é fácil de criar novas instâncias para testes etc. (Ele também permite que testes independentes para executar em paralelo.) Tendo estado em uma instância da máquina é, portanto, um ajuste natural

Há algumas pessoas que acreditam que deve haver não métodos estáticos, não classes estáticas etc. Eu acho que está tomando um pouco longe, mas você deve sempre, pelo menos, consideram o impacto testability de introduzir estática.

Outras dicas

Você não pode usar "this" quando você está trabalhando dentro de um escopo estático, como uma classe estática ou um método estático.

Você tem duas opções aqui. Você pode passar null para o parâmetro "sys". Realmente, este parâmetro, no caso de uma classe estática, não é realmente útil, uma vez que o "remetente" é sempre a classe estática.

Como alternativa, você pode querer considerar fazer seu estado notificador um Singleton . Isso permitirá que você tenha uma única instância de uma classe non-static. Este tem a vantagem de tornar mais fácil a transição para uma implementação não-estático, se as exigências futuras mudanças, também.


Além disso, você realmente deve verificar para se certificar que não são assinantes antes de aumentar este evento. Não fazer isso pode causar problemas:

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

Modificar o delegado:

De:

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

para:

public static delegate void StateChangeHandler(SysInfoEventArgs sysStateInfo);

Eu mudaria este código:

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

para:

public static event Action<SysInfoEventArgs> OnStateChange;

Se você realmente quiser manter a classe estática e usar a semântica de object sender, então a coisa apropriada a passagem seria typeof(Sys). Isso também é análogo ao (antigos e raros) de travamento idioma em uma classe estática.

Mas isso é apenas ser pedante, porque o manipulador de eventos nunca vai usar esse valor e, na prática null iria funcionar tão bem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top