Frage

Es gibt eine Reihe von Fragen, die bereits über die definition von "ref" und "out" - parameter, aber Sie scheinen, wie schlechtes design.Gibt es Fälle, in denen Sie denken, ref Lösung ist die richtige?

Wie es scheint, können Sie immer etwas anderes tun, das sauberer.Kann mir jemand ein Beispiel, wo dies wäre die "beste" Lösung für ein problem?

War es hilfreich?

Lösung

Meiner Meinung nach ist ref für die Schwierigkeit weitgehend kompensierte neue Dienstprogramm Arten erklärt und die Schwierigkeit, „Informationen Anheften auf“ zu bestehenden Informationen, die Dinge, die C # große Schritte in Richtung Adressierung seit seiner Entstehung durch LINQ, Generika genommen haben, und anonyme Typen.

Also nein, ich glaube nicht, es gibt viele klare Anwendungsfälle dafür sind mehr. Ich denke, es ist weitgehend ein Relikt aus, wie die Sprache wurde ursprünglich entworfen.

Ich glaube, dass es Sinn macht immer noch (wie oben erwähnt) in dem Fall, dass Sie irgendeine Art von Fehler-Code von einer Funktion als auch als Rückgabewert zurückkommen müssen, aber sonst nichts (so eine größere Art ist nicht wirklich gerechtfertigt ist.) Wenn ich die ganz über den Platz in einem Projekt zu tun, würde ich wahrscheinlich für Ding-plus-Fehler-Code einig generischen Wrapper definieren, aber in jedem gegebenen Fall ref und out bin in Ordnung.

Andere Tipps

Nun, ref ist für spezielle Fälle im Allgemeinen verwendet, aber ich würde es nicht überflüssig nennen oder eine Legacy-Funktion von C #. Sie werden sehen, es (und out) eine Menge in XNA zum Beispiel verwendet. In XNA ist ein Matrix ein struct und ein ziemlich massiv man an, dass (ich glaube 64 Bytes), und es ist in der Regel am besten, wenn Sie es Funktionen ref passieren 64 Bytes zu vermeiden, kopieren, aber nur 4 oder 8. Ein Spezialisten C # Funktion? Bestimmt. Von nicht viel mehr verwenden oder indikativ für schlechtes Design? Ich bin nicht einverstanden.

Ein Bereich ist bei der Verwendung von kleinen Utility-Funktionen, wie zB:

void Swap<T>(ref T a, ref T b) { T tmp = a; a = b; b = tmp; }  

Ich sehe keine ‚sauberere‘ Alternativen hier. Zugegeben, das ist nicht genau die Architektur-Ebene.

P / Invoke ist der einzige Ort, den ich wirklich an einer Stelle denken können, wo Sie ref oder out verwenden. Andere Fälle können sie bequem sein, aber wie Sie gesagt haben, gibt es im Allgemeinen eine andere, sauberere Art und Weise.

Was, wenn Sie wollte zurück mehrere Objekte, dass für einige unbekannte Grund sind Sie nicht gebunden zusammen in einem einzigen Objekt.

void GetXYZ( ref object x, ref object y, ref object z);

EDIT: divo vorgeschlagen, die Verwendung der OUT-Parameter, die wäre besser geeignet für diese.Ich muss zugeben, er hat einen Punkt.Ich lasse diese Antwort hier als ein, für das Protokoll, dies ist eine inadaquate Lösung.AUS trumps REF in diesem Fall.

Ich denke, die besten Anwendungen sind diejenigen, die Sie in der Regel sehen; müssen Sie sowohl einen Wert und einen „Erfolgsindikatoren“ haben, das nicht eine Ausnahme von einer Funktion ist.

Ein Design-Muster, wo ref nützlich ist, ist ein bidirektionaler Besucher.

Angenommen, Sie eine Storage Klasse hatte, die verwendet werden können, um Werte von verschiedenen Grundtypen zu laden oder zu speichern. Es ist entweder in Load Modus oder Save Modus. Es hat eine Gruppe von überladenen Methoden genannt Transfer, und hier ist ein Beispiel für mit int Werten handeln.

public void Transfer(ref int value)
{
    if (Loading)
        value = ReadInt();
    else
        WriteInt(value);
}

Es würde ähnliche Verfahren für andere primitive Typen -. bool, string, etc

Dann auf einer Klasse, die „übertragbar“ sein muss, würden Sie eine Methode wie folgt schreiben:

public void TransferViaStorage(Storage s)
{
    s.Transfer(ref _firstName);
    s.Transfer(ref _lastName);
    s.Transfer(ref _salary);
}

Das gleiche einzelne Methode kann entweder die Felder aus der Storage laden, oder die Felder in die Storage speichern, je nachdem, welche Art der Storage Objekt ist in.

Wirklich sind die Auflistung einfach alle Felder, die übertragen werden müssen, so nähert sie sich eng deklarative Programmierung statt zwingend notwendig. Das bedeutet, dass Sie nicht zwei Funktionen schreiben müssen (eine zum Lesen, eine zum Schreiben) und da der Entwurf, den ich hier bin mit ist auftragsabhängig, dann ist es sehr praktisch, um sicher zu wissen, dass die Felder immer gelesen werden / in identischer Reihenfolge geschrieben.

Der allgemeine Punkt ist, dass, wenn ein Parameter als ref markiert ist, Sie wissen nicht, ob die Methode es lesen wird oder es zu schreiben, und dies ermöglicht es Ihnen Besucher Klassen zu entwerfen, die in einem von zwei Richtungen arbeiten, Sollte in einer symmetrischen Art und Weise aufgerufen werden (dh mit der besuchten Methode, um nicht zu wissen, in welcher Richtung-Modus der Besucher Klasse arbeitet in).

Vergleich: Attribute + Reflexion

Warum dies stattdessen die Felder zuzuschreiben und Reflexion unter Verwendung von automatisch das Äquivalent von TransferViaStorage zu implementieren? Denn manchmal ist die Reflexion langsam genug, um ein Engpass zu sein (aber immer Profil sicher davon zu sein - es ist so gut wie nie wahr, und Attribute sind viel näher an das Ideal der deklarativen Programmierung).

Die wirkliche Verwendung für diesen ist, wenn Sie eine Struktur erstellen. Structs in C # sind Werttypen und sind daher immer vollständig kopiert, wenn sie von Wert übergeben. Wenn Sie es unter Bezugnahme auf passieren, zum Beispiel aus Performance-Gründen oder weil die Funktion auf die Variable, um Änderungen vorzunehmen braucht, würden Sie das ref-Schlüsselwort verwenden.

Ich konnte sehen, wenn jemand eine Struktur mit 100 Werten (offensichtlich ein Problem bereits) hat, dann würden Sie wahrscheinlich wollen sie durch Verweis übergeben 100 Werte Kopieren zu verhindern. Die und die Rückkehr, dass große Struktur und Schreiben über den alten Wert würde wahrscheinlich haben Performance-Probleme.

Der offensichtliche Grund des „ref“ Schlüsselwort für die Verwendung ist, wenn Sie eine Variable durch Verweis übergeben werden sollen. Zum Beispiel einen Werttyp wie System.Int32 an eine Methode übergeben und ändern es Istwert ist. Eine spezifischere Anwendung könnte sein, wenn Sie zwei Variablen tauschen wollen.

public void Swap(ref int a, ref int b)
{
   ...
}

Der Hauptgrund für die Verwendung des „out“ Schlüsselwort mehr Werte von einer Methode zurückzukehren. Persönlich bevorzuge ich die Werte in einer speziellen Struktur oder Klasse wickeln, da erzeugt die Out-Parameter mit ziemlich hässlich Code. Parameter mit „out“ bestanden - ist wie „ref.“ - geleitet durch Bezugnahme

public void DoMagic(out int a, out int b, out int c, out int d)
{
   ...
}

Es ist ein klarer Fall, wenn Sie das ‚ref‘ Schlüsselwort verwenden. Wenn das Objekt definiert ist, aber nicht außerhalb des Anwendungsbereichs des Verfahrens erstellt, die Sie zu anrufen beabsichtigen, und die Methode, die Sie anrufen möchten, soll die 'new' tun, um es zu erstellen, müssen Sie 'ref' verwenden. e.g.{object a; Funct(a);} {Funct(object o) {o = new object; o.name = "dummy";} wird nicht eine Sache mit object 'a' tun, noch wird es darüber entweder kompilieren oder zur Laufzeit beschweren. Es wird einfach nichts tun. {object a; Funct(ref a);} {Funct(object ref o) {o = new object(); o.name = "dummy";} führt in 'a' mit dem Namen "dummy ein neues Objekt zu sein“. Aber wenn der 'new' schon fertig war, dann nicht erforderlich ref (aber funktioniert, wenn im Lieferumfang enthalten). {object a = new object(); Funct(a);} {Funct(object o) {o.name = "dummy";}

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top