2009-12-11 12 views
6

I seguenti 2 snippet di codice ottengono lo stesso risultato?Queste 2 affermazioni sono identiche?

mio codice originale:

if (safeFileNames != null) 
{ 
    this.SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
} 
else 
{ 
    this.SafeFileNames = false; 
} 

Che pensiero ReSharper era un'idea migliore:

this.SafeFileNames = safeFileNames != null && 
        Convert.ToBoolean(safeFileNames.Value); 

penso che il codice di cui sopra è molto più facile da leggere, qualsiasi motivo valido per cambiare?
Eseguirà più velocemente e, cosa più importante, il codice farà esattamente la stessa cosa?

Anche se si guarda la sezione: Convert.ToBoolean(safeFileNames.Value);, sicuramente questo potrebbe causare un'eccezione di riferimento null?

this.SafeFileNames = bool 

safeFileNames locale è un oggetto personalizzato fortemente tipizzato, ecco la classe:

public class Configuration 
    { 
     public string Name 
     { 
      get; 
      set; 
     } 
     public string Value 
     { 
      get; 
      set; 
     } 
    } 
+3

Non si ottiene una 'NullReferenceExcepton' dal momento che la prima parte dell'istruzione 'safeFileNames! = null' apparirà in cortocircuito e non verrà mai premuto' Convert.ToBoolean (safeFileNames.Value) '- questo è il wa y il && funziona. – Nate

+2

Non causerebbe un'eccezione di riferimento null a causa della valutazione lenta di C#. L'istruzione && viene sempre valutata lato sinistro e lato destro. Ma se il lato sinistro è falso, non si preoccuperà di valutare il lato destro, poiché il risultato logico è già determinato. Quindi, se safeFileNames è null, la chiamata Convert.ToBoolean non viene mai eseguita. Questo genere di cose è abbastanza comune nel codice. –

+1

Quindi se sto capendo il && - se la parte sinistra è falsa restituisce il falso ... altrimenti valuta la parte giusta e restituisce il risultato della parte giusta? –

risposta

24

Il fatto che tu abbia posto la domanda mi suggerisce che il primo è preferito. Cioè, mi sembra che la tua domanda implichi che tu credi che il primo codice sia più facile da capire, e non sei del tutto sicuro che il secondo sia equivalente. Uno degli obiettivi principali della progettazione del software è la gestione della complessità. Se ti sta confondendo ora, potrebbe essere anche a te più tardi, oa chiunque supporti il ​​tuo codice lungo la strada.

+4

Questa è un'ottima risposta. – jason

+0

+1 al BACIO [15] –

+0

Ottimo modo di guardarlo. –

5

Entrambe le affermazioni fanno la stessa identica cosa. Quale usare è una questione di preferenza, ma preferisco la versione di Resharper. Parti più concise, meno mobili. Più facile vedere l'intento del codice.

+0

Cosa succede se this.SafeFileNames è null? Sicuramente provare a convertire. ToBoolean su null, causerebbe un'eccezione di riferimento null? –

+0

@JL: la seconda clausola non verrebbe mai eseguita se SafeFileNames fosse nullo – Randolpho

+0

Cortocircuito per la vittoria. –

1

Sono uguali. Il & & è un operatore di cortocircuito in modo che la seconda parte dell'espressione non valuti se safeFileNames è nullo.

1

Sono uguali. Nel one-liner, se la prima condizione fallisce, la seconda non viene valutata. Quindi non ottieni un riferimento null.

Scommetto che l'IL è lo stesso in entrambi i casi.

Preferisco la seconda versione.

2

Riduce la complessità ciclomatica del codice utilizzando il suggerimento del programma di ricerca.

Se è più facile da leggere o meno, è un'opinione personale, tuttavia preferisco che il suggerimento di resharper ti abbia dato.

Essi sono identici, e se si vuole la leggibilità, potrei anche suggerire il seguente:

if (safeFileNames != null) 
    this.SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
else 
    this.SafeFileNames = false; 

o

this.SafeFileNames = safeFileNames != null ? Convert.ToBoolean(safeFileNames.Value) : false 
+0

Nota: la rimozione di parentesi graffe quando non sono necessarie rende il codice un aspetto migliore, ancora una volta basato su molte opinioni. –

+0

@ Aqutarium, la tua risposta non è errata o inefficiente. Non è così eccitante come gli altri, immagino. Votandoti –

+0

È un'opinione, ma vale la pena notare che StyleCop lo contrassegnerà come un errore. La coerenza è un fattore; l'altro sta introducendo un errore quando si aggiunge la seconda affermazione in un if (senza altro) e si dimentica di aggiungere anche le parentesi. L'IDE di solito la indenta e ti avvisa, ma se ti capita di usare Notepad visivo ... –

1

Yep entrambe queste dichiarazioni farà la stessa cosa, non è necessario devono prendere suggerimenti per i re-sharpers come vangelo, quello che un uomo considera il codice leggibile è un altro casino.

Ci sono alcuni altri modi per fare ciò che il tuo tentativo di fare potrebbe essere più leggibile, quale tipo di valore è safeFileNames? Sembra che potrebbe essere un bool nullable?Se così si potrebbe semplicemente scrivere,

this.SafeFileNames = safeFileNames.GetValueOrDefault(); 
0

Logicamente, sono identici. Qualsiasi differenza di prestazioni sarebbe probabilmente trascurabile. È possibile che il secondo modulo si traduca in codice binario più efficiente su alcune piattaforme poiché il secondo modulo elimina un condizionale. Le condizionali (esecuzione speculativa errata) possono rovinare la pipeline di istruzioni della CPU in un lavoro a uso intensivo della CPU. Tuttavia, sia IL che JITter devono emettere un codice di qualità adeguata per fare molta differenza.

Sono d'accordo con il tuo senso di leggibilità, ma non presumo che tutti lo condividano.

5

Ecco IL per entrambi i pezzi di codice. Ho preso il tuo codice e creato un'app console per dare un'occhiata all'IL. Come si può vedere dall'IL risultante, un metodo (metodo2) è più corto di 4 byte, ma l'IL che viene eseguito per entrambi è praticamente lo stesso, quindi per quanto riguarda le prestazioni ... non preoccuparti di ciò. Entrambi avranno la stessa performance. Concentrati maggiormente su quale è più facile leggere e dimostra meglio le tue intenzioni.

Il mio codice:

class Program 
{ 
    static void Main(string[] args) 
    { 


    } 
    public void method1() 
    { 
     bool? safeFileNames = null; 

     if (safeFileNames != null) 
     { 
      SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
     } 
     else 
     { 
      SafeFileNames = false; 
     } 
    } 
    public void method2() 
    { 
     bool? safeFileNames = null; 
     SafeFileNames = safeFileNames != null && Convert.ToBoolean(safeFileNames.Value); 
    } 
    public static bool SafeFileNames { get; set; } 
} 

L'IL per il metodo 1:

.method public hidebysig instance void method1() cil managed 
{ 
    // Code size  42 (0x2a) 
    .maxstack 1 
    .locals init ([0] valuetype [mscorlib]System.Nullable`1<bool> safeFileNames) 
    IL_0000: ldloca.s safeFileNames 
    IL_0002: initobj valuetype [mscorlib]System.Nullable`1<bool> 
    IL_0008: ldloca.s safeFileNames 
    IL_000a: call  instance bool valuetype [mscorlib]System.Nullable`1<bool>::get_HasValue() 
    IL_000f: brfalse.s IL_0023 
    IL_0011: ldloca.s safeFileNames 
    IL_0013: call  instance !0 valuetype [mscorlib]System.Nullable`1<bool>::get_Value() 
    IL_0018: call  bool [mscorlib]System.Convert::ToBoolean(bool) 
    IL_001d: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0022: ret 
    IL_0023: ldc.i4.0 
    IL_0024: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0029: ret 
} // end of method Program::method1 

La IL per method2:

.method public hidebysig instance void method2() cil managed 
{ 
    // Code size  38 (0x26) 
    .maxstack 1 
    .locals init ([0] valuetype [mscorlib]System.Nullable`1<bool> safeFileNames) 
    IL_0000: ldloca.s safeFileNames 
    IL_0002: initobj valuetype [mscorlib]System.Nullable`1<bool> 
    IL_0008: ldloca.s safeFileNames 
    IL_000a: call  instance bool valuetype [mscorlib]System.Nullable`1<bool>::get_HasValue() 
    IL_000f: brfalse.s IL_001f 
    IL_0011: ldloca.s safeFileNames 
    IL_0013: call  instance !0 valuetype [mscorlib]System.Nullable`1<bool>::get_Value() 
    IL_0018: call  bool [mscorlib]System.Convert::ToBoolean(bool) 
    IL_001d: br.s  IL_0020 
    IL_001f: ldc.i4.0 
    IL_0020: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0025: ret 
} // end of method Program::method2 
+1

Se potessi dare questo più di 1 punto, mi piacerebbe che le persone controllassero l'IL per determinare le differenze effettive. –

+0

+1 per lo sforzo estremo, e molte grazie! –

+0

Sembrava una buona scusa per rispolverare ildasm e giocare un po ':-) – jvilalta

Problemi correlati