2009-04-08 12 views
24

Quando si assegna un default-valore predefinito a un campo (qui falsa ad un bool), FxCop dice:Perché FxCop pensa che l'inizializzazione dei campi sul valore predefinito sia errata?

Resolution : "'Bar.Bar()' initializes field 'Bar.foo' 
       of type 'bool' to false. Remove this initialization 
       because it will be done automatically by the runtime." 

Ora, so che il codice come int a = 0 o bool ok = false è l'introduzione di una certa ridondanza, ma a me sembra una pratica di codice molto, molto buona, quella che i miei insegnanti hanno insistito con rettamente secondo me.

Non solo la penalizzazione delle prestazioni è minima, soprattutto: fare affidamento sull'impostazione predefinita si basa sulla conoscenza di ciascun programmatore di utilizzare sempre una parte di codice, su ogni tipo di dati fornito con un valore predefinito. (DateTime?)

Seriamente, penso che questo sia molto strano: il programma stesso che dovrebbe proteggerti dal fare tutti gli errori troppo ovvi, sta suggerendo qui di crearne uno, solo per un aumento delle prestazioni? (stiamo parlando di codice di inizializzazione qui, eseguito solo una volta! I programmatori che si preoccupano molto, possono ovviamente omettere l'inizializzazione (e probabilmente dovrebbero usare C o assemblatore :-)).

FxCop sta facendo un errore evidente qui, o c'è dell'altro?

due aggiornamenti:

  1. Questa non è solo la mia opinione, ma quello che mi è stato insegnato all'università (Belgio). Non che mi piaccia usare un argumentum ad verecundiam, ma solo per mostrare che non è solo il mio parere . E riguardo che:

  2. Le mie scuse, ho appena trovato questo:

    Should I always/ever/never initialize object fields to default values?

+0

Non penso che ci sia anche un vantaggio in termini di prestazioni dall'omitare l'inizializzazione. –

+0

Sono d'accordo con Martinho, ma mi piace la tua domanda! –

+1

@ Martin Fernandes: C'è un vantaggio in termini di prestazioni di omettere questo - vedi la mia risposta e l'articolo di riferimento. –

risposta

12

Non ci possono essere vantaggi prestazionali significativi da questo, in alcuni casi. Per i dettagli, see this CodeProject article.

Il problema principale è che non è necessario in C#. In C++, le cose sono diverse, così molti professori insegnano che dovresti sempre inizializzare. Il modo in cui gli oggetti sono inizializzati è cambiato in .NET.

In .NET, gli oggetti vengono sempre inizializzati quando costruiti. Se si aggiunge un inizializzatore, è possibile (tipico) che si verifichi una doppia inizializzazione delle variabili. Ciò accade se li si inizializza nel costruttore o in linea.

Inoltre, poiché l'inizializzazione non è necessaria in .NET (succede sempre, anche se non si dice esplicitamente di inizializzare al valore predefinito), l'aggiunta di un inizializzatore suggerisce, dal punto di vista della leggibilità, che si sta tentando di aggiungere codice che ha una funzione. Ogni pezzo di codice dovrebbe avere uno scopo, o essere rimosso se non necessario. Il codice "extra", anche se innocuo, suggerisce che è lì per un motivo, che riduce la manutenibilità.

+2

non necessario per chi o cosa? Ovviamente il codice per le persone, anche perché i commenti di una macchina non sono necessari, questo non significa che non siano perse inutili. – Peter

+0

È possibile inserirlo come commento, con la stessa facilità di un'istruzione, e non creare gli stessi impatti sulle prestazioni. È come avere un codice irraggiungibile - potrebbe fornirti qualcosa, ma preferirei farlo come un commento piuttosto che lasciare un codice irraggiungibile nei miei metodi. –

+1

La differenza con un commento, è quando dico int i = 0; Voglio essere zero, l'affermazione è logica. Anche se compilato con un futuro compilatore che ha altre impostazioni predefinite (improbabile per il corso) – Peter

2

Non si basa su alcun programmatore che conosca uno "standard aziendale" definito localmente che potrebbe cambiare in qualsiasi momento, ma su qualcosa definito formalmente nello standard. Si potrebbe anche dire "non usare x++ perché questo si basa sulla conoscenza di ogni programmatore.

+0

problemi completamente diversi, (tra() ha un valore DateTime predefinito e qual è il suo valore? Che cosa fa x--? Penso che la risposta al secondo 100% dei programmatori sappia, la risposta al primo - se siamo fortunati - 50%) – Peter

+0

Prima di tutto, è uguale a "default (DateTime)". Secondo, in quali circostanze ti interesserebbe quale sia il valore reale? –

2

È necessario ricordare che le regole FxCop sono solo linee guida, non sono indissociabili. Si dice anche così sulla pagina per la descrizione della regola lei ha citato (http://msdn.microsoft.com/en-us/library/ms182274(VS.80).aspx, sottolineatura mia):

Quando escludere Avvertenze:

escludere un avviso da questa regola se il costruttore chiama un altro costruttore in la stessa o la classe base che inizializza il campo con un valore non predefinito. È inoltre sicuro escludere un avviso da questa regola o disabilitare completamente la regola, se le prestazioni e la manutenzione del codice non sono priorità.

Ora, la regola non è del tutto errata, ma come si dice, questa non è una priorità per te, quindi basta disabilitare la regola.

3

FX Cop lo vede come aggiunta di codice non necessario e il codice non necessario è negativo. Sono d'accordo con te, mi piace vedere a cosa serve, penso che sia più facile da leggere.

Un problema simile che incontriamo è, per motivi di documentazione si può creare un costruttore vuoto come questo

/// <summary> 
/// a test class 
/// </summary> 
/// <remarks>Documented on 4/8/2009 by richard</remarks> 
public class TestClass 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="TestClass"/> class. 
    /// </summary> 
    /// <remarks>Documented on 4/8/2009 by Bob</remarks> 
    public TestClass() 
    { 
     //empty constructor 
    }   
} 

Il compilatore crea automaticamente questo costruttore, in modo da poliziotto FX si lamenta, ma le nostre regole di documentazione di castelli di sabbia richiede tutti i metodi pubblici a essere documentato, quindi abbiamo solo detto al poliziotto di non lamentarsi.

+0

codice non necessario è ovviamente sbagliato, ma questo codice può diventare necessario nell'improbabile evento in cui un valore predefinito verrà modificato in futuro e questo codice verrà ricompilato. – Peter

+0

@Peter: i valori predefiniti per i tipi di valore sono garantiti per l'inizializzazione sempre a zero. Fa parte della specifica CLR stessa. Non è possibile modificare un valore di default. I tipi di riferimento sono uguali: sono garantiti, in base alle specifiche, come predefiniti su null. –

+0

@Bob Il bidello, fare cose che non si sentono giusto solo per soddisfare uno strumento di solito finisce male! ;) –

5

FxCop deve fornire regole per tutti, quindi se questa regola non ti interessa, basta escluderla.

Ora, suggerirei che se si desidera dichiarare esplicitamente un valore predefinito, utilizzare una costante (o una variabile readonly statica) per farlo. Sarà ancora più chiaro dell'inizializzazione con un valore e FXCop non si lamenterà.

private const int DEFAULT_AGE = 0; 

private int age = 0; // FXCop complains 
private int age = DEFAULT_AGE; // FXCop is happy 

private static readonly DateTime DEFAULT_BIRTH_DATE = default(DateTime); 

private DateTime birthDate = default(DateTime); // FXCop doesn't complain, but it isn't as readable as below 
private DateTime birthDate = DEFAULT_BIRTH_DATE; // Everyone's happy 
+0

tx (è stato anche suggerito in un precedente commento) – Peter

5

Reed Copsey said specificando i valori di default per le prestazioni campi impatti, e lui si riferisce a a test from 2005.

public class A 
{ 
    // Use CLR's default value 
    private int varA; 
    private string varB; 
    private DataSet varC; 
} 

public class B 
{ 
    // Specify default value explicitly 
    private int varA = 0; 
    private string varB = null; 
    private DataSet varC = null; 
} 

Ora otto anni e quattro versioni di C# e .NET dopo ho deciso di ripetere che prova in .NET Framework 4.5 e C# 5, compilato come uscita con le ottimizzazioni predefinite utilizzando Visual Studio 2012. Sono rimasto sorpreso di vedere che esiste ancora una differenza di prestazioni tra l'inizializzazione esplicita dei campi con i loro valori predefiniti e non la specifica di un valore predefinito. Mi sarei aspettato che i successivi compilatori C# ottimizzassero quei compiti costanti ormai.

 
No init: 512,75 Init on Def: 536,96 Init in Const: 720,50 
Method No init: 140,11 Method Init on Def: 166,86 

(the rest)

Così ho sbirciato all'interno dei costruttori di classi A e B in questo test, e entrambi sono vuoti:

.method public hidebysig specialname rtspecialname 
    instance void .ctor() cil managed 
{ 
    // Code size 7 (0x7) 
    .maxstack 8 

    IL_0000: ldarg.0 
    IL_0001: call instance void [mscorlib]System.Object::.ctor() 
    IL_0006: ret 
} // end of method .ctor 

potevo non trovare un motivo nell'IL perché l'assegnazione esplicita di valori costanti predefiniti ai campi con dedicare più tempo Apparentemente il compilatore C# fa ottimizzare le costanti di distanza, e ho il sospetto che lo abbia sempre fatto.

Quindi, il test deve essere errato ... Ho scambiato il contenuto delle classi A e B, scambiato i numeri nella stringa del risultato e rieseguito i test. E lo ed ecco improvvisamente specificando i valori predefiniti è più veloce.

 
No init: 474,75 Init on Def: 464,42 Init in Const: 715,49 
Method No init: 141,60 Method Init on Def: 171,78 

(the rest)

Pertanto concludo che il compilatore C# ottimizza correttamente per il caso in cui si assegnano i valori predefiniti ai campi. Non fa alcuna differenza di prestazioni!


Ora sappiamo prestazioni sono davvero non un problema. E sono d'accordo con Reed Copsey's statement "Il codice di 'extra', anche se era innocuo, suggerisce che è lì per un motivo, che riduce manutenibilità." E d'accordo con Anders Hansson su questo:

pensare a lungo termine Manutenzione.

  • Mantenere il codice più esplicito possibile.
  • Non fare affidamento su modalità specifiche per la lingua da inizializzare se non è necessario. Forse una versione più recente della lingua funzionerà diversamente?
  • I futuri programmatori ti ringrazieranno.
  • La gestione ti ringrazierà.
  • Perché offuscare le cose anche il minimo?

I futuri manutentori possono provenire da uno sfondo diverso. In realtà non si tratta di ciò che è "giusto", è più ciò che sarà più facile nel lungo periodo.

Problemi correlati