Come posso evitare questi if ripetitivi annidati?

4

Sto cercando di implementare un'interfaccia web per un database utente. Gli ospiti possono creare ospiti per i loro corsi, gli ospiti possono essere cancellati dopo che il corso è terminato, ma devono rimanere nel database per un dato periodo di tempo. Se un host tenta di creare un guest già esistente nel database, possono verificarsi le seguenti cose:

  • Il guest è già attivo ed è stato creato dallo stesso host,
  • Il guest è già attivo ed è stato creato da un host diverso,
  • Il guest è nello stato eliminato ed è stato creato dallo stesso host,
  • Il guest è nello stato eliminato ed è stato creato da un host diverso.

Attualmente sto cercando di rappresentare lo stato dell'utente in questo enumer:

public enum GuestUserStatus
{
    Unknown = 0,
    NewGuest = 1,

    ActiveSameHost = 10,
    ActiveDifferentHost = 11,

    DeletedSameHost = 20,
    DeletedDifferentHost = 21
}

Questo mi permette di switch() sullo stato utente impostato.

Tuttavia, per impostare lo stato dell'utente, attualmente sto usando repetetive se clausole come queste:

if (queriedUser.GuestDetails.Creator == creator)
{
    if (queriedUser.GuestDetails.State == GuestState.Deleted)
    {
        currentStatus = GuestUserStatus.DeletedSameHost;
    }
    else
    {
        currentStatus = GuestUserStatus.ActiveSameHost;
    }
}
else
{
    if (queriedUser.GuestDetails.State == GuestState.Deleted)
    {
        currentStatus = GuestUserStatus.DeletedDifferentHost;
    }
    else
    {
        currentStatus = GuestUserStatus.ActiveDifferentHost;
    }
}

Le clausole if annidate agiscono sulla stessa condizione ma con un risultato diverso.

C'è un modo per evitarlo? Ho esaminato l'enumerazione con [Flags] e utilizzando le potenze di 2 come valori sottostanti, ma successivamente non ho più potuto utilizzare switch() .

AGGIORNAMENTO: Si noti che ho le stesse condizioni due volte e risultati diversi per loro.

UPDATE2: provare ad indirizzare la domanda collegata Come per affrontare un anti-pattern a freccia "ramificato"? : Diciamo che implemento la risposta accettata di quella domanda. Questo mi darebbe qualcosa del genere:

 bool activeSameHost = (queriedUser.Guest.Creator == creator && queriedUser.GuestDetails.State != GuestState.Deleted);
 bool activeDifferentHost = (queriedUser.Guest.Creator == creator && queriedUser.GuestDetails.State == GuestState.Deleted);
 bool inactiveSameHost = (queriedUser.Guest.Creator != creator && queriedUser.GuestDetails.State == GuestState.Deleted);
 bool inativeDifferentHost = (queriedUser.Guest.Creator != creator && queriedUser.GuestDetails.State == GuestState.Deleted);

if(activeSameHost) currentStatus = GuestUserStatus.ActiveSameHost;
if(inactiveSameHost) currentStatus = GuestUserStatus.InactiveSameHost;
if(activeDifferentHost) currentStatus = GuestUserStatus.ActiveDifferentHost;
if(inactiveDifferentHost) currentStatus = GuestUserStatus.InactiveDifferentHost;

Non riesco a vedere il miglioramento. Certo, if s non è più nidificato, ma l'unica cosa che è cambiata è la complessità che si sposta dalla% nidificata co_de nidificata all'assegnazione di variabili intermedie.

    
posta Thaoden 10.03.2015 - 09:30
fonte

2 risposte

11

Puoi utilizzare [Flags] e switch allo stesso tempo, semplicemente definendo un alias per la combinazione di flag che ti interessa.

[Flags]
public enum GuestUserStatus
{
    Unknown = 0,
    NewGuest = 1,

    NotNew = 2, // I need this to distinguish from the Unknown and NewGuest states.
    Deleted = 4,
    DifferentHost = 8,

    ActiveSameHost = NotNew,
    ActiveDifferentHost = NotNew | DifferentHost,

    DeletedSameHost = NotNew | Deleted,
    DeletedDifferentHost = NotNew | Deleted | DifferentHost,
}

Tuttavia, in un progetto del genere, proverei a mettere lo stato NotNew a 0 anziché Unknown , ma non conosco i tuoi requisiti. (Cosa c'è di sbagliato nel modellarlo con due booleani?)

    
risposta data 10.03.2015 - 09:46
fonte
1

Utilizzare le azioni di lamdba è un'altra opzione.

Ecco un metodo di base che controlla la presenza di condizionali e esegue il codice appropriato - ma si noti che nei parametri di stato e di creatore ho fatto una lunga ripresa al loro tipo: non sono necessari bene. Basta illustrare il concetto.

private void SetConditionalValue(Enum state, string guestCreator, string creator, Action activeSameHost, Action inactiveSameHost, Action activeDifferentHost, Action inactiveDifferentHost)
{
    if (guestCreator == creator)
    {
        if (state == GuestState.Deleted)
        {
           inactiveSameHost.Invoke();
        }
        else
        {
            activeSameHost.Invoke();
        }
    }
    else
    {
        if (state == GuestState.Deleted)
        {
            inactiveDifferentHost.Invoke();
        }
        else
        {
            activeDifferentHost.Invoke();
        }
    }
}

Ora le chiamate hanno questo aspetto:

SetConditionalValue(queriedUser.GuestDetails.State, 
                    queriedUser.Guest.Creator, 
                    creator,
                    () => currentStatus = GuestUserStatus.ActiveSameHost, 
                    () => currentStatus = GuestUserStatus.InactiveSameHost,
                    () => currentStatus = GuestUserStatus.ActiveDifferentHost,
                    () => currentStatus = GuestUserStatus.InactiveDifferentHost);  

È quindi possibile riutilizzare lo stesso metodo per azioni diverse con la stessa condizione:

SetConditionalValue(queriedUser.GuestDetails.State, 
                    queriedUser.Guest.Creator, 
                    creator,
                    () => subscriptionCost = 130d, 
                    () => subscriptionCost = 215d,
                    () => subscriptionCost = 125d,
                    () => subscriptionCost = 100d); 

Le condizioni verranno rivalutate, ma non devi preoccuparti di scrivere nuovamente ogni volta. Se la condizione cambia leggermente in seguito, si modifica in un punto e il resto viene influenzato automaticamente. Naturalmente è possibile passare ai delegati per avere più controllo e parametri di riferimento, ma se tutto è locale non è necessario. Puoi mescolarlo con una valutazione preliminare delle condizioni nel tuo aggiornamento, ma penso che il pieno if condizionale sia più leggibile e sostenibile.

    
risposta data 11.03.2015 - 13:10
fonte

Leggi altre domande sui tag