C # stellt das Schlüsselwort ref
und bereit out
, um Argumente als Referenz zu übergeben. Die Semantik der beiden ist sehr ähnlich. Der einzige Unterschied besteht in der Initialisierung der Flaged Variable:
ref
erfordert, dass die Variable initialisiert wird, bevor sie an die Funktion übergeben wird,out
nicht.out
erfordert, dass die Variable innerhalb der Funktion initialisiert wird,ref
nicht.
Die Verwendungsfälle dieser beiden Schlüsselwörter sind auch fast gleich, und ihre zu häufige Verwendung wird meines Erachtens als Codegeruch angesehen (obwohl es gültige Verwendungsfälle wie die TryParse
und TryGetValue
Muster gibt).
Könnte aus diesem Grund jemand erklären, warum es in C # zwei sehr ähnliche Tools für so enge Anwendungsfälle gibt?
Unter MSDN wird außerdem angegeben, dass sie ein unterschiedliches Laufzeitverhalten aufweisen:
Obwohl die Schlüsselwörter ref und out ein unterschiedliches Laufzeitverhalten verursachen, werden sie beim Kompilieren nicht als Teil der Methodensignatur betrachtet.
Wie unterscheidet sich ihr Laufzeitverhalten?
Fazit
Beide Antworten sehen richtig aus, danke euch beiden. Ich habe die von jmoreno akzeptiert , weil sie expliziter ist.
quelle
ref
in C ++ implementiert . auf Zeiger auf den fraglichen Objektzeiger (oder das fragliche Grundelement). dhInt32.TryParse(myStr, out myInt)
(C #) wird auf die gleiche Weise wieint32_tryParse(myStr, &myInt)
(C) "ausgeführt" ; Der einzige Unterschied sind einige Einschränkungen, die vom Compiler erzwungen werden, um Fehler zu vermeiden. (Ich werde dies nicht als Antwort posten, weil ich mich vielleicht irre, wie dies hinter den Kulissen funktioniert, aber ich stelle mir das so vor [weil es Sinn macht])Antworten:
Zum Zeitpunkt der Beantwortung dieser Frage war der MSDN-Artikel auf subtile Weise falsch ( seitdem wurde er korrigiert ). Anstelle von "anderes Verhalten verursachen" sollte es "anderes Verhalten erfordern" sein.
Insbesondere erzwingt der Compiler unterschiedliche Anforderungen für die beiden Schlüsselwörter, obwohl derselbe Mechanismus (IL) zum Aktivieren des Verhaltens verwendet wird.
quelle
out
Parameters oder Nichtzuweisung eines Parameters suchtref
, aber die von ihm ausgegebene IL ist nur eine Referenz. Ist das korrekt?out T
undref T
in anderen CLI-Sprachen wie VB.Net oder C ++ / CLI identisch gerendert werden.Hier ist ein interessanter Artikel zum Thema, der Ihre Frage beantworten könnte:
http://www.dotnetperls.com/ref
Sehenswürdigkeit:
"Der Unterschied zwischen ref und out liegt nicht in der Common Language Runtime, sondern in der C # -Sprache selbst."
aktualisieren:
Der leitende Entwickler meiner Arbeit hat gerade die Antwort von @ jmoreno bestätigt.
quelle
string
das alles zu tun?Laufzeit ? Absolut keine. Sie können eine Methode nicht mit denselben Parametern überladen, die sich nur durch das Schlüsselwort ref oder out unterscheiden.
Wenn Sie versuchen, dies zu kompilieren, wird der Kompilierungsfehler "Methode mit derselben Signatur ist bereits deklariert" angezeigt:
Um diese Frage zu beantworten: "... warum gibt es in C # zwei sehr ähnliche Tools für so enge Anwendungsfälle?"
Aus Sicht der Codelesbarkeit und der API besteht ein großer Unterschied. Als Benutzer der API weiß ich, dass die API bei Verwendung von "out" nicht vom out-Parameter abhängt. Als API-Entwickler bevorzuge ich das "out" und benutze "ref" nur, wenn es absolut (SELTEN!) Notwendig ist. Siehe diese Referenz für eine großartige Diskussion:
/programming/1516876/when-to-use-ref-vs-out
Hintergrundinformation: Ich habe die folgende Methode kompiliert und zerlegt. Ich habe die Schlüsselwörter ref und out verwendet (in diesem Beispiel out), aber der Assemblycode hat sich nicht geändert, außer bei einem Adressverweis, wie ich es erwartet hätte:
00000000 Push EBP
00000001 mov EBP, ESP
00000003 Push EDI-
00000004 Push esi
00000005 Push ebx
00000006 sub esp, 34h
00000009 xor eax, eax
0000000b mov dword ptr [EBP-10H], eax
0000000e mov dword ptr [EBP-1Ch] EAX
00000011 mov dword ptr [ebp-3Ch], ecx
00000014 mov dword ptr [ebp-40h], edx
00000017 cmp dword ptr ds: [008B1710h], 0
0000001e je 00000025
00000020 call 6E6B601E
00000025
nop param = 0;
00000026 mov eax, dword ptr [ebp-40h]
00000029 xor edx, edx
0000002b mov dword ptr [eax], edx
}
0000002d nop
0000002e lea esp, [ebp-0Ch]
00000031 pop ebx
00000032 pop esi
00000033 pop edi
00000034 pop ebp
00000035 ret
Lese ich die Versammlung richtig?
quelle