Impilabile parole chiave l'una sull'altra - stile scadente? [chiuso]

2

Mi sono sempre chiesto questo, specialmente nei linguaggi in stile C / Java. Ad esempio, considera le prime 3 righe di questo codice C #:

lock (serviceLock)
using (var client = new ServiceClient())
try
{
    // Do something
    client.DoSomething();
}

catch (System.ServiceModel.FaultException ex)
{
    // Handle error
    addLog(ex.ToString());
}

Questo uso mi è sempre sembrato alquanto discutibile. Tuttavia, l'alternativa non è molto pratica (3+ livelli di indentazione per una chiamata di servizio). Oltre all'estetica pura, c'è qualche ragione pratica per aggiungere o non aggiungere le parentesi aggiuntive in questo caso?

    
posta user74130 18.12.2013 - 04:36
fonte

6 risposte

0

I blocchi lock e using sono per comodità del programmatore, ma non sono richiesti. Se trovi codice meno rientrato più facile da leggere. Puoi scrivere la stessa cosa usando la versione non-code delle stesse caratteristiche di C #.

Monitor.Enter(serviceLock);
var client = new ServiceClient();
try
{
    client.DoSomething();
}
catch(FaultException ex)
{
    addLog(ex.ToString());
}
finally
{
    Monitor.Exit(serviceLock);
    client.Dispose();
}

Quanto sopra fa la stessa cosa, ma non c'è alcun problema di leggibilità o confusione su ciò che sta facendo.

L'approccio alternativo è quello di utilizzare blocchi e suddividere tutto in funzioni separate.

public function foo()
{
    lock(serviceLock)
    {
        fooService();
    }
}

private function fooService()
{
    using(ServiceClient client = new ServiceClient())
    {
        fooClientTry(client);
    }
}

private function fooClientTry(ServiceClient client)
{
    try
    {
        fooClient(client);
    }
    catch(System.ServiceModel.FaultException ex)
    {
        addLog(ex.ToString());
    }
}

private function fooClient(ServiceClient client)
{
    // work....
}

Preferisco l'approccio sopra. Sembra molto più lavoro / codice ma è più facile da mantenere perché ogni funzione svolge una singola attività. Quando entri in più blocchi annidati, questo approccio mantiene tutto solo alcune rientranze.

    
risposta data 19.12.2013 - 01:08
fonte
14

Ti suggerisco caldamente di utilizzare tre livelli di rientro nidificato. Quando guardo rapidamente questo codice, vedo solo il blocco catch () {}, vedo un blocco match try {} e ignoro il fatto che esiste un blocco e un'istruzione using. Ora, quando guardo il codice con più attenzione, ho notato che ci sono parole chiave sopra il try, ma il loro ambito potrebbe non essere immediatamente evidente per me - sono solo per il blocco try, o sono per il try / prendere la dichiarazione? Se è necessario aggiungere del codice a un certo punto, posso quasi garantire che qualcuno manchi il blocco o l'uso delle istruzioni (lo stesso motivo per cui la maggior parte degli standard di codifica che ho visto proibiscono di posizionare solo una riga dopo un'istruzione if e non usare parentesi graffe). Vorrei andare con il codice più specifico, che è tre livelli di indentazione utilizzando parentesi appropriate in modo che l'ambito sia immediatamente comprensibile.

Se la rientranza ti disturba tanto, ti suggerisco di usare 2 spazi invece di tab (che dovrebbe essere un'opzione nel tuo IDE). È qualcosa che ho imparato nel mio lavoro, e sono davvero innamorato di come lo uso. È molto più conciso che avere un gap di due pollici perché sei rientrato quattro volte.

    
risposta data 18.12.2013 - 05:37
fonte
12

Direi che sono contrario. Verrò in giro e aggiungerò del codice dopo try...catch senza notare che avrei dovuto estendere l'ambito di lock .

E, cosa più importante, questa versione non riduce veramente il rientro!

Solo nasconde . La nidificazione profonda è principalmente un problema logico, non estetico.

Il fatto che lo vediamo brutto è il risultato di una cattiva pratica di programmazione; non viceversa.

(L'estetica di per sé è relativa - ad es. questa risposta a risposta elevata afferma che "profondamente annidato dichiarazioni strutturali - "punte di freccia" - erano, in lingue come Pascal, una volta viste come codice bello. ")

Tre livelli sono ancora validi, ma se raggiungi, ad esempio, sette livelli, la rimozione di parentesi graffe da lock e using e il deindentamento risolve il problema?

Al contrario, desensibilizza lo sviluppatore al problema, riducendo così la possibilità che qualcuno possa andare avanti e ridefinire la cosa.

    
risposta data 18.12.2013 - 12:20
fonte
6

Per un'opinione dissidente, preferisco questa pratica con un cambiamento significativo.

lock (serviceLock) using (var client = new ServiceClient()) try
{
    // Do something
    client.DoSomething();
}
catch (System.ServiceModel.FaultException ex)
{
    // Handle error
    addLog(ex.ToString());
}

Non impilando, obbliga l'occhio a leggere fino in fondo come una lunga dichiarazione. Se la linea è troppo lunga o non legge bene, allora sai di voler riorganizzare la logica.

Lo faccio spesso con doppi loop e for-loops con try catch blocks.

for (int i = 0; i < x.Length; ++i) for (int j = 0; j < x[i].Length; ++j) try
{
    // each cell in a ragged matrix: x[i][j]
}
catch (/* … */)
{
    // exception in one cell allowing other cells to be processed.
}

Soprattutto, la chiarezza è la cosa più importante. Se sei rigido con qualsiasi stile, in alcuni casi finirai con codice brutto e illeggibile. Sii flessibile in un modo che ti permetta di evidenziare la logica. Se non sai se qualcosa è chiaro, chiedi ai tuoi co-sviluppatori di guardarlo. Chiedi loro cosa fa il codice senza spiegarglielo.

    
risposta data 19.12.2013 - 02:09
fonte
3

Non ho alcun problema con l'impilamento di serrature e ustioni, ma il try-catch deve essere racchiuso tra parentesi graffe. Ciò richiederà di pensare quale sia l'ambito dell'istruzione using in questo contesto.

lock (serviceLock)
using (var client = new ServiceClient())
{
  try
  {
      client.DoSomething();
  }    
  catch (System.ServiceModel.FaultException ex)
  {
      addLog(ex.ToString());
  }
}

Impiego parole chiave tutte le volte (principalmente% bit di% bit anche roba come using e fixed ) perché a volte aggiungerei sei o più parentesi graffe. Non c'è modo di leggerlo a colpo d'occhio e dire quale coppia corrisponde a quale. Inoltre aumenta il rischio che il codice per il tuo metodo non si adatti allo schermo. Neanche questo è buono per la leggibilità.

    
risposta data 18.12.2013 - 09:21
fonte
1

La regola è semplice. L'indentazione deve essere coerente con l'ambito. Il lock si applica fino alla fine del blocco catch e deve essere simile. Non ho familiarità con la parola chiave using in C # ma dal tuo codice la stessa regola sembra applicare.

    
risposta data 19.12.2013 - 03:14
fonte

Leggi altre domande sui tag