2010-08-03 9 views
11

Fondamentalmente creo una classe leggera, è passata in circa 10 parametri, non cambia questi parametri, li memorizza solo localmente quando si è nel costruttore.Passa per valore vs Passa per rendimento di riferimento C# .net

Alcuni sono tipi di riferimento (stringhe, classi) altri sono tipi di valori (int, bool, enumerati).

La mia domanda è: devo passare tutto questo (tranne le mie classi) con la parola chiave "ref"?

La mia considerazione qui è la prestazione.

+0

Non vedo come possa essere d'aiuto. Anche se "ref" fa risparmiare tempo nel copiare una struct, non puoi mantenere "ref" come membri della classe, "ref" è utile solo all'interno di un metodo. – Kobi

+0

possibile duplicato di [C# 'ref' parola chiave, prestazioni] (http://stackoverflow.com/questions/900903/c-sharp-ref-keyword-performance) – nawfal

risposta

16

Utilizzare solo ref se il metodo ha bisogno di modificare i parametri, e questi cambiamenti devono essere passati al codice chiamante. Si dovrebbe ottimizzare questo solo se è stato eseguito attraverso un profiler e determinato che il collo di bottiglia è effettivamente il CLR che copia i parametri del metodo nello stack.

Tenere presente che il CLR è fortemente ottimizzato per chiamare metodi con parametri, quindi non dovrei pensare che questo sarebbe il problema.

3

Se la classe tiene solo i parametri forse dovresti usare una struct?

Forse questo è di interesse?

When to use struct?

6

No. Per i tipi di riferimento, si sta già passando un riferimento, non è necessario passare il riferimento per riferimento a meno che non si desideri modificare il riferimento a, ad es. assegnagli un nuovo oggetto Per i tipi di valore, è possibile passare per riferimento, ma a meno che non si verifichi un problema di prestazioni, non lo farei. Soprattutto se i tipi in questione sono piccoli (4 byte o meno), c'è poco o nessun guadagno in termini di prestazioni, forse anche una penalità.

+1

È a mia conoscenza che c'è sempre una perdita di prestazioni quando si passano tipi di valore per riferimento, perché i tipi di valore devono essere inseriti in una scatola. Per quanto ho capito (dal meraviglioso C# In Depth, dal altrettanto meraviglioso @JonSkeet) passare un tipo di valore come parametro di riferimento non causerà mai un aumento di prestazioni, al contrario causerà sempre una diminuzione delle prestazioni. –

+0

@BenH: _ "c'è sempre una perdita di prestazioni quando si passano tipi di valori per riferimento, perché i tipi di valore devono essere racchiusi tra parentesi" _ - no. sembra che tu stia confondendo passando per riferimento con il riferimento _a_ che passa. Non sono la stessa cosa. L'uso di 'ref' con un tipo di valore non inserisce il valore. Passa un riferimento (puntatore) alla variabile che contiene il valore. –

+0

@PeterDuniho: All'interno di .NET, passare un argomento per riferimento passa un "byref". Non ho visto questo termine usato molto nelle discussioni, ma penso che ci sarebbe meno confusione se fosse usato più spesso, dal momento che suona molto meno come "riferimento all'oggetto" della frase "passa per riferimento". – supercat

3

No. I parametri di passaggio per riferimento aggiungono overhead, quindi diminuirebbero le prestazioni.

+0

Sono abituato al C++ quindi potrei essere totalmente sbagliato ma potresti approfondirlo di più? Diciamo che ho un oggetto enorme, wouldnt: pass per riferimento, basta passare un indirizzo dei dati invece di dover copiare l'oggetto completo? –

+0

@SvenvandenBoogaart non lo si sta affrontando. Stai creando un nuovo puntatore all'interno del metodo per mantenere il valore dell'oggetto. Ma la modifica del valore del puntatore non modificherà il puntatore esterno utilizzato per passare questo valore alla chiamata al metodo. –

2

Per quanto ho capito, hai una classe con solo campi e un costruttore che assegna i parametri a quei campi, giusto?

Se questo è il caso, prenderei in considerazione l'uso di ref nella cattiva pratica del costruttore. Se si assegna il parametro a un campo in quella classe, viene comunque memorizzato in base al valore. Quindi se non si modifica il valore nel costruttore non è necessario utilizzarlo per riferimento.

+0

+1: esattamente ciò che non ho potuto esprimere nel mio commento. – Kobi

3

Ho trovato su chiamate di funzione ad alto volume per i tipi di valore più grande che passando per ref era più veloce, leggermente. Se hai un volume elevato di chiamate di funzione e hai bisogno di velocità, questa potrebbe essere una considerazione. Sono aperto a prove alternative.

public static void PassValue(decimal value) 
{ 

} 

public static void PassRef(ref decimal value) 
{ 

}    

decimal passMe = 0.00010209230982047828903749827394729385792342352345m; 

for (int x = 0; x < 20; x++) 
{ 
    DateTime start = DateTime.UtcNow; 
    TimeSpan taken = new TimeSpan(); 

    for (int i = 0; i < 50000000; i++) 
    { 
     PassValue(passMe); 
    } 

    taken = (DateTime.UtcNow - start); 
    Console.WriteLine("Value : " + taken.TotalMilliseconds); 

    start = DateTime.UtcNow; 

    for (int i = 0; i < 50000000; i++) 
    { 
     PassRef(ref passMe); 
    } 

    taken = (DateTime.UtcNow - start); 
    Console.WriteLine("Ref : " + taken.TotalMilliseconds); 
} 

Risultati:

Value : 150 
Ref : 140 
Value : 150 
Ref : 143 
Value : 151 
Ref : 143 
Value : 152 
Ref : 144 
Value : 152 
Ref : 143 
Value : 154 
Ref : 144 
Value : 152 
Ref : 143 
Value : 154 
Ref : 143 
Value : 157 
Ref : 143 
Value : 153 
Ref : 144 
Value : 154 
Ref : 147 
Value : 153 
Ref : 144 
Value : 153 
Ref : 144 
Value : 153 
Ref : 146 
Value : 152 
Ref : 144 
Value : 153 
Ref : 143 
Value : 153 
Ref : 143 
Value : 153 
Ref : 144 
Value : 153 
Ref : 144 
Value : 152 
Ref : 143 
0

non sono sicuro per C#, ma per C++/C dipende da ciò che si sta passando. Se stai passando un tipo di base (int, float, double, char) .... allora il passaggio per valore è più veloce quindi passa per riferimento (perché la funzione call è ottimizzata per questo. Se stai passando qualcosa di più grande, una classe grande , un array, una stringa lunga ... quindi il passaggio per riferimento è molto, molto più veloce perché se si sta facendo un int [100000], allora il processore dovrà allocare un chunk di 100000 x 32/64 (a seconda dell'architettura), e quindi copia tutti i valori sopra, ci vuole un sacco di tempo.Mentre per riferimento passa semplicemente un puntatore

C# astrae la maggior parte di questa distanza, quindi non so cosa faccia, ma penso che ciò che si applica a C++/c in termini di efficienza di solito può essere applicato a C#.

Problemi correlati