Ich finde es merkwürdig, dass dir null.ToString()der Name gegeben wird wtf. Warum überrascht dich das? Sie können eine Instanzmethode nicht aufrufen, wenn Sie überhaupt nichts zum Aufrufen haben.
BoltClock
11
@BoltClock: Natürlich ist es möglich, eine Instanzmethode für eine Nullinstanz aufzurufen. Nur nicht möglich in C #, aber sehr gültig in der CLR :)
Leppie
1
Die Antworten in Bezug auf String.Concat sind fast richtig. Tatsächlich handelt es sich bei dem spezifischen Beispiel in der Frage um eine konstante Faltung , und die Nullen in der ersten Zeile werden vom Compiler entfernt, dh sie werden zur Laufzeit nie ausgewertet, weil sie nicht mehr vorhanden sind. Der Compiler hat sie gelöscht. Ich habe hier einen kleinen Monolog über alle Regeln für die Verkettung und das ständige Falten von Strings geschrieben, um weitere Informationen zu erhalten: stackoverflow.com/questions/9132338/… .
Chris Shain
77
Sie können einer Zeichenfolge nichts hinzufügen, aber Sie können aus nichts eine Zeichenfolge machen.
RGB
Ist die zweite Aussage ungültig? class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
Bei Verkettungsoperationen von Zeichenfolgen behandelt der C # -Compiler eine Nullzeichenfolge genauso wie eine leere Zeichenfolge, konvertiert jedoch nicht den Wert der ursprünglichen Nullzeichenfolge.
Der Operator binär + führt eine Zeichenfolgenverkettung durch, wenn einer oder beide Operanden vom Typ Zeichenfolge sind.
Wenn ein Operand der Zeichenfolgenverkettung null ist, wird eine leere Zeichenfolge ersetzt. Andernfalls wird jedes Nicht-String-Argument durch Aufrufen der ToStringvom Typ-Objekt geerbten virtuellen Methode in seine String-Darstellung konvertiert .
Wenn ToStringzurückgegeben wird null, wird eine leere Zeichenfolge ersetzt.
Der Grund für den Fehler in der Sekunde ist:
null (C # -Referenz) - Das Schlüsselwort null ist ein Literal, das eine Nullreferenz darstellt, die sich nicht auf ein Objekt bezieht. null ist der Standardwert von Variablen vom Referenztyp.
Würde das dann funktionieren? var wtf = ((String)null).ToString();Ich arbeite kürzlich in Java, wo das Casting von Nullen möglich ist. Es ist eine Weile her, seit ich mit C # gearbeitet habe.
Jochem
14
@Jochem: Sie versuchen immer noch, eine Methode für ein Nullobjekt aufzurufen, also rate ich nein. Betrachten Sie es als null.ToString()vs ToString(null).
Svish
@Svish ja, jetzt denke ich wieder daran, es ist ein Null-Objekt, also hast du recht, es wird nicht funktionieren. In Java auch nicht: Nullzeigerausnahme. Keine Ursache. Tnx für deine Antwort! [edit: hat es in Java getestet: NullPointerException. Mit dem Unterschied, dass es mit cast kompiliert wird, ohne cast nicht].
Jochem
Im Allgemeinen gibt es keinen Grund, das Schlüsselwort null absichtlich zu konatieren oder zu ändern. Wenn Sie eine leere Zeichenfolge benötigen, verwenden Sie string.Empty. Wenn Sie überprüfen müssen, ob eine Zeichenfolgenvariable null ist, können Sie entweder (myString == null) oder string.IsNullOrEmpty (myString) verwenden. Alternativ können Sie eine Null-String-Variable in einen String umwandeln. Leer verwenden Sie myNewString = (myString == null ?? string.Empty)
csauve
@Jochem Casting wird es kompilieren lassen, aber es wird tatsächlich eine NullReferenceException zur Laufzeit
auslösen
108
Weil der +Operator in C # intern in übersetzt String.Concat, was eine statische Methode ist. Und diese Methode wird zufällig nullwie eine leere Zeichenfolge behandelt. Wenn Sie sich die Quelle von String.Concatin Reflector ansehen , werden Sie es sehen:
// while looping through the parameters
strArray[i]=(str ==null)?Empty: str;// then concatenate that string array
Auf der anderen Seite ToString()handelt es sich um eine Instanzmethode, die Sie nicht aufrufen können null(für welchen Typ sollte sie verwendet werden null?).
Es gibt jedoch keinen + -Operator in der String-Klasse. Ist es also der Compiler, der in String.Concat übersetzt?
Superlogical
@superlogical Ja, das macht der Compiler. Tatsächlich ist der +Operator für Zeichenfolgen in C # nur syntaktischer Zucker für String.Concat.
Botz3000
Hinzu kommt: Der Compiler wählt automatisch die Überladung von Concat aus, die am sinnvollsten ist. Verfügbare Überladungen sind 1, 2 oder 3 Objektparameter, 4 Objektparameter + __arglistund eine paramsObjektarray-Version.
Wormbo
Welches String-Array wird dort geändert? Erstellt Concatimmer ein neues Array von Nicht-Null-Zeichenfolgen, selbst wenn ein Array von Nicht-Null-Zeichenfolgen angegeben wird, oder ist etwas anderes im Gange?
Supercat
@supercat Das geänderte Array ist ein neues Array, das dann an eine private Hilfsmethode übergeben wird. Sie können den Code selbst mit einem Reflektor anzeigen.
Botz3000
29
Das erste Beispiel wird übersetzt in:
var bob =String.Concat("abc123",null,null,null,"abs123");
Die ConcatMethode überprüft die Eingabe und übersetzt null als leere Zeichenfolge
Das zweite Beispiel wird übersetzt in:
var wtf =((object)null).ToString();
Hier wird also eine nullReferenzausnahme generiert
Eigentlich wird ein AccessViolationExceptiongeworfen :)
Leppie
Ich habe es gerade getan :) ((object)null).ToString()=> AccessViolation((object)1 as string).ToString()=>NullReference
Leppie
1
Ich habe NullReferenceException. DN 4.0
Viacheslav Smityukh
Interessant. Wenn ich ((object)null).ToString()in ein try/catchstecke, bekomme ich NullReferenceExceptionauch.
Leppie
3
@Ieppie, außer dass AccessViolation auch nicht ausgelöst wird (warum sollte das so sein?) - NullReferenceException hier.
Jeroenh
11
Der erste Teil Ihres Codes wird einfach so behandelt in String.Concat,
Dies ist, was der C # -Compiler aufruft, wenn Sie Zeichenfolgen hinzufügen. " abc" + nullwird übersetzt in String.Concat("abc", null),
und intern ersetzt diese Methode nulldurch String.Empty. Deshalb löst Ihr erster Teil des Codes keine Ausnahme aus. es ist einfach so
var bob ="abc"+string.Empty+string.Empty+string.Empty+"123";//abc123
Und im zweiten Teil Ihres Codes wird eine Ausnahme ausgelöst, da 'null' kein Objekt ist. Das Schlüsselwort null ist ein Literal, das eine Nullreferenz darstellt , die auf kein Objekt verweist. null ist der Standardwert von Variablen vom Referenztyp.
Und ' ToString()' ist eine Methode, die von einer Instanz eines Objekts aufgerufen werden kann, jedoch kein Literal.
String.Emptyist nicht gleich null. Es wird in einigen Methoden genauso behandelt wie String.Concat. Wenn Sie beispielsweise eine Zeichenfolgenvariable auf gesetzt haben null, wird diese durch C # nicht ersetzt, String.Emptywenn Sie versuchen, eine Methode dafür aufzurufen.
Botz3000
3
Fast. nullwird nicht wie String.Emptyvon C # behandelt, sondern nur wie in String.ConcatC, was der C # -Compiler beim Hinzufügen von Zeichenfolgen aufruft. "abc" + nullwird übersetzt String.Concat("abc", null)und intern ersetzt diese Methode nulldurch String.Empty. Der zweite Teil ist völlig richtig.
Botz3000
9
In dem COM-Framework, das vor .net stand, musste jede Routine, die eine Zeichenfolge erhielt, diese freigeben, wenn sie damit fertig war. Da es sehr häufig vorkam, dass leere Zeichenfolgen in Routinen und aus Routinen übergeben wurden und der Versuch, einen Nullzeiger "freizugeben", als legitime Nichtstun-Operation definiert wurde, entschied Microsoft, dass ein Nullzeichenfolgenzeiger eine leere Zeichenfolge darstellt.
Um eine gewisse Kompatibilität mit COM zu gewährleisten, interpretieren viele Routinen in .net ein Nullobjekt als rechtliche Darstellung als leere Zeichenfolge. Mit ein paar geringfügigen Änderungen an .net und seinen Sprachen (insbesondere wenn Instanzmitglieder angeben können, dass sie nicht als virtuell aufgerufen werden sollen) hätte Microsoft nullObjekte vom deklarierten Typ String noch mehr wie leere Strings verhalten können. Wenn Microsoft das getan hätte, hätte es auch die Nullable<T>Arbeit etwas anders gestalten müssen (um zuzulassen - etwas, Nullable<String>was sie meiner Meinung nach sowieso hätten tun sollen) und / oder einen NullableStringTyp definieren müssen, der größtenteils austauschbar Stringwäre, aber a nicht berücksichtigt nullals gültige leere Zeichenfolge.
So wie es ist, gibt es einige Kontexte, in denen ein nullWille als legitimer leerer String angesehen wird, und andere, in denen dies nicht der Fall ist. Keine schrecklich hilfreiche Situation, aber eine, die Programmierer kennen sollten. Im Allgemeinen schlagen Ausdrücke des Formulars stringValue.someMemberfehl, wenn dies der Fall stringValueist null. Die meisten Framework-Methoden und -Operatoren, die Zeichenfolgen als Parameter akzeptieren, werden jedoch nullals leere Zeichenfolge betrachtet.
'+'ist ein Infix-Operator. Wie jeder Operator ruft er wirklich eine Methode auf. Sie können sich eine Nicht-Infix-Version vorstellen"wow".Plus(null) == "wow"
Der Implementierer hat sich für so etwas entschieden ...
Wirklich, es ist eher so var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");. Operatorüberladungen sind im Kern statische Methoden: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Wären sie nicht var bob = null + "abc";oder string bob = null + null;wären sie insbesondere nicht gültig.
Ben Mosher
Du hast recht, ich hatte nur das Gefühl, ich wäre zu verwirrend, wenn ich es so erkläre.
Nigel Thorne
3
Ich denke, weil es ein Literal ist, das sich auf kein Objekt bezieht. ToString()braucht eine object.
Jemand sagte in diesem Diskussionsthread, dass man aus nichts einen String machen kann.
(Das ist ein schöner Satz, wie ich denke). Aber ja - Sie können :-), wie das folgende Beispiel zeigt:
var x =null+(string)null;var wtf = x.ToString();
funktioniert gut und löst überhaupt keine Ausnahme aus. Der einzige Unterschied besteht darin, dass Sie eine der Nullen in eine Zeichenfolge umwandeln müssen. Wenn Sie die Umwandlung (Zeichenfolge) entfernen , wird das Beispiel weiterhin kompiliert, es wird jedoch eine Laufzeitausnahme ausgelöst : "Operator '+' ist für Operanden von nicht eindeutig Geben Sie '<null>' und '<null>' "ein.
Hinweis: Im obigen Codebeispiel ist der Wert von x nicht wie erwartet null, sondern eine leere Zeichenfolge, nachdem Sie einen der Operanden in eine Zeichenfolge umgewandelt haben.
Eine weitere interessante Tatsache ist, dass in C # / .NET die nullBehandlung nicht immer gleich ist, wenn Sie unterschiedliche Datentypen betrachten. Beispielsweise:
int? x =1;// string x = "1";
x = x +null+null;Console.WriteLine((x==null)?"<null>": x.ToString());
Betrachten Sie die erste Zeile des Code-Snippets: Wennx es sich um eine nullbare Ganzzahlvariable (dh int?) handelt, die einen Wert enthält 1, erhalten Sie das Ergebnis <null>zurück. Wenn es sich um eine Zeichenfolge (wie im Kommentar gezeigt) mit Wert handelt "1", erhalten Sie "1"eher zurück als <null>.
NB Auch interessant: Wenn Sie var x = 1;für die erste Zeile verwenden, wird ein Laufzeitfehler angezeigt. Warum? Weil die Zuweisung die Variable xin den Datentyp verwandelt int, der nicht nullwertfähig ist. Der Compiler geht hier nicht davon int?aus und schlägt daher in der 2. Zeile wo fehlnull hinzugefügt wird.
Das Hinzufügen nullzu einer Zeichenfolge wird einfach ignoriert. null(in Ihrem zweiten Beispiel) ist keine Instanz eines Objekts, daher gibt es nicht einmal eine ToString()Methode. Es ist nur ein Wortlaut.
Weil es keinen Unterschied zwischen string.Emptyund nullwann Sie Zeichenfolgen konkatieren. Sie können auch null übergeben string.Format. Sie versuchen jedoch, eine Methode aufzurufen null, die immer zu a führt NullReferenceExceptionund daher einen Compilerfehler generiert.
Wenn Sie es aus irgendeinem Grund wirklich tun möchten, können Sie eine Erweiterungsmethode schreiben, die nach sucht nullund dann zurückgibt string.Empty. Eine solche Erweiterung sollte aber nur verwendet werden, wenn dies absolut notwendig ist (meiner Meinung nach).
Allgemein: Je nach Spezifikation kann es gültig sein, null als Parameter zu akzeptieren, aber es ist immer ungültig, eine Methode für null aufzurufen.
Dies ist ein weiteres Thema, warum die Operanden des Operators + bei Zeichenfolgen null sein können. Dies ist eine Art VB-Sache (sorry Leute), um Programmierern das Leben zu erleichtern, oder wenn der Programmierer nicht mit Nullen umgehen kann. Ich stimme dieser Spezifikation überhaupt nicht zu. 'unbekannt' + 'irgendetwas' sollte immer noch 'unbekannt' sein ...
null.ToString()
der Name gegeben wirdwtf
. Warum überrascht dich das? Sie können eine Instanzmethode nicht aufrufen, wenn Sie überhaupt nichts zum Aufrufen haben.class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
Antworten:
Der Grund für die erste Arbeit:
Von MSDN :
Weitere Informationen zum + Binäroperator :
Der Grund für den Fehler in der Sekunde ist:
null (C # -Referenz) - Das Schlüsselwort null ist ein Literal, das eine Nullreferenz darstellt, die sich nicht auf ein Objekt bezieht. null ist der Standardwert von Variablen vom Referenztyp.
quelle
wtf = ((String)null).ToString();
Ich arbeite kürzlich in Java, wo das Casting von Nullen möglich ist. Es ist eine Weile her, seit ich mit C # gearbeitet habe.null.ToString()
vsToString(null)
.Weil der
+
Operator in C # intern in übersetztString.Concat
, was eine statische Methode ist. Und diese Methode wird zufällignull
wie eine leere Zeichenfolge behandelt. Wenn Sie sich die Quelle vonString.Concat
in Reflector ansehen , werden Sie es sehen:(MSDN erwähnt es auch: http://msdn.microsoft.com/en-us/library/k9c94ey1.aspx )
Auf der anderen Seite
ToString()
handelt es sich um eine Instanzmethode, die Sie nicht aufrufen könnennull
(für welchen Typ sollte sie verwendet werdennull
?).quelle
+
Operator für Zeichenfolgen in C # nur syntaktischer Zucker fürString.Concat
.__arglist
und eineparams
Objektarray-Version.Concat
immer ein neues Array von Nicht-Null-Zeichenfolgen, selbst wenn ein Array von Nicht-Null-Zeichenfolgen angegeben wird, oder ist etwas anderes im Gange?Das erste Beispiel wird übersetzt in:
Die
Concat
Methode überprüft die Eingabe und übersetzt null als leere ZeichenfolgeDas zweite Beispiel wird übersetzt in:
Hier wird also eine
null
Referenzausnahme generiertquelle
AccessViolationException
geworfen :)((object)null).ToString()
=>AccessViolation
((object)1 as string).ToString()
=>NullReference
((object)null).ToString()
in eintry/catch
stecke, bekomme ichNullReferenceException
auch.Der erste Teil Ihres Codes wird einfach so behandelt in
String.Concat
,Dies ist, was der C # -Compiler aufruft, wenn Sie Zeichenfolgen hinzufügen. "
abc" + null
wird übersetzt inString.Concat("abc", null)
,und intern ersetzt diese Methode
null
durchString.Empty
. Deshalb löst Ihr erster Teil des Codes keine Ausnahme aus. es ist einfach soUnd im zweiten Teil Ihres Codes wird eine Ausnahme ausgelöst, da 'null' kein Objekt ist. Das Schlüsselwort null ist ein Literal, das eine Nullreferenz darstellt , die auf kein Objekt verweist. null ist der Standardwert von Variablen vom Referenztyp.
Und '
ToString()
' ist eine Methode, die von einer Instanz eines Objekts aufgerufen werden kann, jedoch kein Literal.quelle
String.Empty
ist nicht gleichnull
. Es wird in einigen Methoden genauso behandelt wieString.Concat
. Wenn Sie beispielsweise eine Zeichenfolgenvariable auf gesetzt habennull
, wird diese durch C # nicht ersetzt,String.Empty
wenn Sie versuchen, eine Methode dafür aufzurufen.null
wird nicht wieString.Empty
von C # behandelt, sondern nur wie inString.Concat
C, was der C # -Compiler beim Hinzufügen von Zeichenfolgen aufruft."abc" + null
wird übersetztString.Concat("abc", null)
und intern ersetzt diese Methodenull
durchString.Empty
. Der zweite Teil ist völlig richtig.In dem COM-Framework, das vor .net stand, musste jede Routine, die eine Zeichenfolge erhielt, diese freigeben, wenn sie damit fertig war. Da es sehr häufig vorkam, dass leere Zeichenfolgen in Routinen und aus Routinen übergeben wurden und der Versuch, einen Nullzeiger "freizugeben", als legitime Nichtstun-Operation definiert wurde, entschied Microsoft, dass ein Nullzeichenfolgenzeiger eine leere Zeichenfolge darstellt.
Um eine gewisse Kompatibilität mit COM zu gewährleisten, interpretieren viele Routinen in .net ein Nullobjekt als rechtliche Darstellung als leere Zeichenfolge. Mit ein paar geringfügigen Änderungen an .net und seinen Sprachen (insbesondere wenn Instanzmitglieder angeben können, dass sie nicht als virtuell aufgerufen werden sollen) hätte Microsoft
null
Objekte vom deklarierten Typ String noch mehr wie leere Strings verhalten können. Wenn Microsoft das getan hätte, hätte es auch dieNullable<T>
Arbeit etwas anders gestalten müssen (um zuzulassen - etwas,Nullable<String>
was sie meiner Meinung nach sowieso hätten tun sollen) und / oder einenNullableString
Typ definieren müssen, der größtenteils austauschbarString
wäre, aber a nicht berücksichtigtnull
als gültige leere Zeichenfolge.So wie es ist, gibt es einige Kontexte, in denen ein
null
Wille als legitimer leerer String angesehen wird, und andere, in denen dies nicht der Fall ist. Keine schrecklich hilfreiche Situation, aber eine, die Programmierer kennen sollten. Im Allgemeinen schlagen Ausdrücke des FormularsstringValue.someMember
fehl, wenn dies der FallstringValue
istnull
. Die meisten Framework-Methoden und -Operatoren, die Zeichenfolgen als Parameter akzeptieren, werden jedochnull
als leere Zeichenfolge betrachtet.quelle
'+'
ist ein Infix-Operator. Wie jeder Operator ruft er wirklich eine Methode auf. Sie können sich eine Nicht-Infix-Version vorstellen"wow".Plus(null) == "wow"
Der Implementierer hat sich für so etwas entschieden ...
Also ... dein Beispiel wird
das ist das gleiche wie
Null wird zu keinem Zeitpunkt zu einer Zeichenfolge. Das
null.ToString()
ist also nicht andersnull.VoteMyAnswer()
. ;)quelle
var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");
. Operatorüberladungen sind im Kern statische Methoden: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Wären sie nichtvar bob = null + "abc";
oderstring bob = null + null;
wären sie insbesondere nicht gültig.Ich denke, weil es ein Literal ist, das sich auf kein Objekt bezieht.
ToString()
braucht eineobject
.quelle
Jemand sagte in diesem Diskussionsthread, dass man aus nichts einen String machen kann. (Das ist ein schöner Satz, wie ich denke). Aber ja - Sie können :-), wie das folgende Beispiel zeigt:
funktioniert gut und löst überhaupt keine Ausnahme aus. Der einzige Unterschied besteht darin, dass Sie eine der Nullen in eine Zeichenfolge umwandeln müssen. Wenn Sie die Umwandlung (Zeichenfolge) entfernen , wird das Beispiel weiterhin kompiliert, es wird jedoch eine Laufzeitausnahme ausgelöst : "Operator '+' ist für Operanden von nicht eindeutig Geben Sie '<null>' und '<null>' "ein.
Hinweis: Im obigen Codebeispiel ist der Wert von x nicht wie erwartet null, sondern eine leere Zeichenfolge, nachdem Sie einen der Operanden in eine Zeichenfolge umgewandelt haben.
Eine weitere interessante Tatsache ist, dass in C # / .NET die
null
Behandlung nicht immer gleich ist, wenn Sie unterschiedliche Datentypen betrachten. Beispielsweise:Betrachten Sie die erste Zeile des Code-Snippets: Wenn
x
es sich um eine nullbare Ganzzahlvariable (dhint?
) handelt, die einen Wert enthält1
, erhalten Sie das Ergebnis<null>
zurück. Wenn es sich um eine Zeichenfolge (wie im Kommentar gezeigt) mit Wert handelt"1"
, erhalten Sie"1"
eher zurück als<null>
.NB Auch interessant: Wenn Sie
var x = 1;
für die erste Zeile verwenden, wird ein Laufzeitfehler angezeigt. Warum? Weil die Zuweisung die Variablex
in den Datentyp verwandeltint
, der nicht nullwertfähig ist. Der Compiler geht hier nicht davonint?
aus und schlägt daher in der 2. Zeile wo fehlnull
hinzugefügt wird.quelle
Das Hinzufügen
null
zu einer Zeichenfolge wird einfach ignoriert.null
(in Ihrem zweiten Beispiel) ist keine Instanz eines Objekts, daher gibt es nicht einmal eineToString()
Methode. Es ist nur ein Wortlaut.quelle
Weil es keinen Unterschied zwischen
string.Empty
undnull
wann Sie Zeichenfolgen konkatieren. Sie können auch null übergebenstring.Format
. Sie versuchen jedoch, eine Methode aufzurufennull
, die immer zu a führtNullReferenceException
und daher einen Compilerfehler generiert.Wenn Sie es aus irgendeinem Grund wirklich tun möchten, können Sie eine Erweiterungsmethode schreiben, die nach sucht
null
und dann zurückgibtstring.Empty
. Eine solche Erweiterung sollte aber nur verwendet werden, wenn dies absolut notwendig ist (meiner Meinung nach).quelle
Allgemein: Je nach Spezifikation kann es gültig sein, null als Parameter zu akzeptieren, aber es ist immer ungültig, eine Methode für null aufzurufen.
Dies ist ein weiteres Thema, warum die Operanden des Operators + bei Zeichenfolgen null sein können. Dies ist eine Art VB-Sache (sorry Leute), um Programmierern das Leben zu erleichtern, oder wenn der Programmierer nicht mit Nullen umgehen kann. Ich stimme dieser Spezifikation überhaupt nicht zu. 'unbekannt' + 'irgendetwas' sollte immer noch 'unbekannt' sein ...
quelle