Se la condizione non è vera: valore predefinito o altra clausola? [chiuso]

3

Ho cercato Programmer e Stackoverflow e non sono riuscito a trovare una risposta soddisfacente, anche se sono abbastanza sicuro che sia stato chiesto molte volte in passato. La domanda che ho trovato ha solo risposte che riguardano solo la leggibilità. I seguenti estratti di codice provengono dal codice C # che stavo scrivendo.

Quando si ha a che fare con una variabile locale che ha qualche valore calcolato quando una condizione è vera ma un valore predefinito altrimenti, io:

Prima imposta il valore, quindi modifica il valore quando la condizione è vera?

short version = 1;      // <-- set the value here.
if (separator != -1)
{
    version = Int16.Parse(filename.Substring(separator + 1));
    filename = filename.Substring(0, separator);
}

Oppure non imposta il valore e aggiungi un altro quando la condizione è falsa?

short version;
if (separator != -1)
{
    version = Int16.Parse(filename.Substring(separator + 1));
    filename = filename.Substring(0, separator);
}
else
    version = 1;        // <-- set the value here.

Un programmatore potrebbe avere aspettative sbagliate di fronte a una delle due soluzioni (ad esempio quando la clausola if è abbastanza grande e la clausola else è molto discendente, fuori dalla vista)? Hai qualche esperienza in cui la differenza contava? Perché uno stile particolare viene applicato alla tua azienda e perché? Ci sono motivi tecnici per cui si preferirebbe l'uno rispetto all'altro? Il primo imposta una variabile due volte, ma non sono sicuro se ciò sarebbe importante nei moderni ottimizzatori di compilazione.

    
posta Daniel Pelsmaeker 12.08.2012 - 01:27
fonte

7 risposte

10

C'è una scuola di pensiero che dice che una variabile non dovrebbe entrare nel campo di applicazione fino a quando non è possibile assegnargli un valore valido. In altre parole, la variabile dovrebbe mai contenere un valore errato o un valore non valido. Ciò impedisce la possibilità, ad esempio, di un manutentore che successivamente effettua una chiamata dopo la dichiarazione della variabile ma prima che la variabile sia inizializzata correttamente.

Nel tuo breve esempio, è abbastanza ovvio che queste affermazioni sono un gruppo, ma nel tempo non c'è nulla che impedisca alle persone di inserire diverse dichiarazioni non correlate tra loro.

Ciò significa che entrambi dei tuoi esempi sono sbagliati. Il primo modo ha un breve periodo di tempo in cui mantiene erroneamente il valore predefinito e il secondo modo ha un breve periodo di tempo in cui non contiene correttamente alcun valore. La migliore soluzione dal punto di vista della leggibilità e della manutenibilità è qualcosa come:

short version = getVersion(filename, separator);

Questo ha il vantaggio aggiuntivo di conformarsi alla "scuola dovrebbe fare esattamente una cosa sola" scuola di pensiero.

    
risposta data 12.08.2012 - 03:24
fonte
7

Vorrei incapsulare la funzionalità nel suo metodo e utilizzare una clausola di salvaguardia per occuparmi del caso speciale:

private short getVersion(String filename, int separator)
{
    if (separator == -1)
    {
        return 1;
    }

    return Int16.Parse(filename.Substring(separator + 1));
}

Ho omesso la modifica del nome file perché probabilmente merita anche il suo metodo:

private String removeVersion(String filename, int separator)
{
    if (separator == -1)
    {
        return filename;
    }

    return filename.Substring(0, separator);
}

Il mio C # è arrugginito, ma si spera che sia abbastanza corretto da dare un senso.

    
risposta data 12.08.2012 - 03:16
fonte
2

Hai escluso una terza possibilità:

short version;
if (separator == -1)
{
    version = 1;        // <-- set the value here.
}
 else
{
    version = Int16.Parse(filename.Substring(separator + 1));
    filename = filename.Substring(0, separator);
}

Come noti, il compilatore non si preoccupa davvero di quale strada vai. Il modo in cui l'ho messo qui, almeno non hai la separazione di cui eri preoccupato. L'impostazione della versione tra vero e falso è evidente a colpo d'occhio, quella in alto sarà sempre bella e breve, e rende evidente l'impostazione della versione in ogni caso - se è questo che ti preoccupa.

Penso che troverai (con i numerosi voti per chiudere) che è davvero solo una questione di preferenza.

    
risposta data 12.08.2012 - 01:55
fonte
1

È più chiaro quando si racchiude il compito all'interno di un blocco if-else se è pertinente alla condizione stessa. Non solo è possibile suggerire al compilatore che l'assegnazione può essere ignorata nel caso in cui la condizione non riesca, ma suggerisce anche al programmatore che le due cose (assegnazione di una variabile e la condizione) sono correlate. Allo stesso modo, se i due non sono correlati, la loro separazione (assegnazione prima o dopo il blocco if ()) sarebbe probabilmente l'approccio intuitivo. Naturalmente, tutto dipende dal contesto ed è specifico del caso. Ma in generale legare insieme le cose ed essere elaborate con la logica.

    
risposta data 12.08.2012 - 02:42
fonte
1

Quando vado alla macchina, quale pulsante dovrei premere: Caffè o Tè? Beh, dipende da cosa voglio bere : caffè o tè ...: -)

  • Quando voglio esprimere che la variabile "var" è di default dovrebbe ottenere il valore "A", ma in alcuni casi può essere "B" o "C", ho impostato il valore di inizializzazione su "A" .

  • Quando il codice è responsabile di impostare "var" su un valore specifico senza alcun valore predefinito, lo lascio non inizializzato - che darà anche un bel avvertimento del compilatore se c'è un percorso dimenticato. Sebbene non abbia mai usato questa tecnica, la parola chiave 'final' può garantire che la variabile sia inizializzata solo una volta (in Java).

Ma ciò che suggerisco di non omettere mai è il {} intorno a QUALSIASI blocco (anche se "può essere una singola affermazione" dalla definizione del linguaggio). Ho già perso troppo tempo in cose del tipo "Ho pensato che sarebbe stata una sola riga" o "Non sapevo che ci sarebbe stato un altro se-altro intorno / dentro questo", nei miei e nei codici degli altri. Il rientro non è un'operazione del compilatore, ma un piacere per gli occhi, anche se l'IDE lo supporta. Quando crei un blocco, notifica al compilatore a riguardo ... digitare altri due caratteri non fa così male.

    
risposta data 12.08.2012 - 08:12
fonte
0

PER FAVORE CONDIVIDI DI PIÙ CODICE: una classe completa se adatta. Altrimenti, non c'è modo di darti un consiglio decente.

Non so esattamente cosa stai facendo, quindi suppongo. Ecco un modo ... cosa fa la variabile separatore? Idealmente il separatore dovrebbe essere passato come parametro, ma non ha senso perché se separatore è -1, non dovrebbe essere stato chiamato in primo luogo.

// Initialize some stuff inside of the constructor.

...
private void ParseVersionAndFileName()
{
    if (this.Separator < 0)
    {
        Debug.Assert(separator == -1, "Negative value but not -1? How?");
        return;
    }

    this.Version = Int16.Parse(this.Filename.Substring(this.Separator + 1));
    this.Filename = this.Filename.Substring(0, this.Separator);
}

public string Version
{
    get;
    private set;
}

public int Version
{
    get;
    private set;
}
...
    
risposta data 12.08.2012 - 02:20
fonte
0

C'è la prospettiva dell'architettura hardware. Scrivendo il codice inizializzando ed evitando il ramo nella clausola else, si evita di inquinare gratuitamente la tabella di previsione del ramo. Per il tuo esempio relativamente banale, non importa perché non importa quello che fai, devi fare il confronto e il ramo.

    
risposta data 12.08.2012 - 07:25
fonte

Leggi altre domande sui tag