2010-08-03 19 views
11

Ich bin im Grunde eine leichte Klasse erstellen, ist es in etwa 10 Parameter übergeben, es ändert sich nicht diese Parameter, es speichert sie nur lokal, wenn im Konstruktor.Pass by Wert vs Pass by Referenz Leistung C#. NET

Einige sind Referenztypen (Strings, Klassen) andere sind Werttypen (int, bool, enums).

Meine Frage ist, sollte ich diese alle (außer meine Klassen) mit dem Schlüsselwort "Ref" weitergeben?

Meine Überlegung hier ist Leistung.

+0

Ich sehe nicht, wie es hilft. Auch wenn 'ref' Zeit spart, eine Struktur zu kopieren, können Sie 'ref's nicht als Klassenmitglieder behalten,' ref' ist nur innerhalb einer Methode nützlich. – Kobi

+0

möglich Duplikat von [C# 'ref' Schlüsselwort, Leistung] (http://stackoverflow.com/questions/900903/c-sharp-ref-keyword-performance) – nawfal

Antwort

16

Nur ref verwenden, wenn die Methode, die Parameter ändern, muss, und diese Änderungen müssen auf den anrufenden Code übergeben werden. Sie sollten dies nur optimieren, wenn Sie es durch einen Profiler ausgeführt haben und festgestellt haben, dass der Engpass in der Tat die CLR ist, die die Methodenparameter auf den Stapel kopiert.

Bedenken Sie, dass die CLR für das Aufrufen von Methoden mit Parametern stark optimiert ist, also sollte ich nicht denken, dass dies das Problem wäre.

3

Wenn die Klasse nur Parameter enthält, sollten Sie vielleicht eine Struktur verwenden?

Vielleicht ist das von Interesse?

When to use struct?

6

Nein. Bei Referenztypen übergeben Sie bereits eine Referenz, es ist nicht erforderlich, die Referenz als Referenz zu übergeben, es sei denn, Sie möchten ändern, worauf die Referenz verweist, z. weise ihm ein neues Objekt zu. Für Werttypen können Sie als Referenz übergeben werden, aber wenn Sie kein Leistungsproblem haben, würde ich dies nicht tun. Insbesondere wenn die in Frage stehenden Typen klein sind (4 Bytes oder weniger), gibt es wenig oder keinen Leistungsgewinn, möglicherweise sogar eine Strafe.

+1

Es ist mein Verständnis, dass es immer einen Leistungsverlust gibt, wenn Werttypen übergeben werden als Referenz, weil die Werttypen eingerahmt werden müssen. Soweit ich es verstehe (aus dem wunderbaren C# In Depth, durch das ebenso wunderbare @JonSkeet), wird das Übergeben eines Wertetyps als Referenzparameter niemals zu einer Leistungssteigerung führen, im Gegenteil, es wird immer eine Leistungsminderung verursachen. –

+0

@BenH: _ "Es gibt immer einen Leistungsverlust, wenn Werttypen als Referenz übergeben werden, da die Werttypen eingerahmt werden müssen" _ - nein. du scheinst verwirrend zu sein, indem du auf Referenz gehst. Sie sind nicht gleich. Wenn Sie 'ref' mit einem Werttyp verwenden, wird der Wert nicht berücksichtigt. Es übergibt einen Verweis (Zeiger) an die Variable, die den Wert enthält. –

+0

@PeterDuniho: Innerhalb der Interna von .NET übergibt die Übergabe eines Arguments per Referenz ein "byref". Ich habe diesen Begriff nicht oft in Diskussionen verwendet, aber ich denke, dass es weniger Verwirrung geben würde, wenn es häufiger verwendet würde, da es viel weniger wie "Objektreferenz" klingt als die Phrase "pass by reference". – supercat

3

Nein. Das Übergeben von Parametern per Referenz erhöht den Overhead, sodass nur die Leistung verringert wird.

+0

Ich bin an C++ gewöhnt, also könnte ich total falsch liegen, aber könnten Sie das mehr ausarbeiten? Nehmen wir an, ich hätte ein riesiges Objekt, würde nicht: als Referenz übergeben nur eine Adresse der Daten übergeben, anstatt das komplette Objekt kopieren zu müssen? –

+0

@SvenvandenBoogaart Sie bewältigen es nicht. Sie erstellen einen neuen Zeiger innerhalb der Methode, um Objektwert zu halten. Durch Ändern des Zeigerwerts wird jedoch nicht der äußere Zeiger geändert, mit dem dieser Wert an den Methodenaufruf übergeben wird. –

2

Soweit ich verstehe, haben Sie eine Klasse mit nur Feldern und einem Konstruktor, der die Parameter diesen Feldern zuweist, oder?

Wenn das der Fall ist, würde ich ref im Konstruktor schlechte Praxis verwenden. Wenn Sie den Parameter einem Feld in dieser Klasse zuweisen, wird er in jedem Fall als Wert gespeichert. Wenn Sie also den Wert im Konstruktor nicht ändern, brauchen Sie ihn nicht als Referenz zu verwenden.

+0

+1 - genau das, was ich in meinem Kommentar nicht artikulieren konnte. – Kobi

3

Ich fand auf High-Volume-Funktionsaufrufen für größere Werttypen, dass die Übergabe von Ref schneller war, leicht. Wenn Sie eine große Anzahl von Funktionsaufrufen haben und Geschwindigkeit benötigen, könnte dies eine Überlegung sein. Ich bin offen für alternative Beweise.

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); 
} 

Ergebnisse:

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

Ich bin für C#, aber für C++/c es hängt davon ab, was Sie vorbei nicht sicher. Übergeben Sie einen Basistyp (int, float, double, char) .... dann ist die Übergabe nach Wert schneller als die Referenzübergabe (weil Funktionsaufrufe dafür optimiert sind. Wenn Sie etwas Größeres übergeben, eine große Klasse , ein Array, ein langer String ... dann ist die Übergabe durch Referenz viel, viel schneller, denn wenn Sie einen Int [100000] tun, muss der Prozessor einen 100000 x 32/64 (je nach Architektur) Chunk zuweisen und dann kopiere alle Werte, das kostet viel Zeit.Während durch Verweis nur einen Zeiger passiert

C# abstrahiert die meisten davon weg, so dass ich nicht weiß, was es tut, aber ich denke, was für C++/c in Bezug auf Effizienz gilt, kann normalerweise für C# gelten.

Verwandte Themen