String.Empty kann nicht als Standardwert für einen optionalen Parameter verwendet werden

89

Ich lese Effective C # von Bill Wagner. In Punkt 14 - Minimieren der Logik für die doppelte Initialisierung zeigt er das folgende Beispiel für die Verwendung der neuen optionalen Parameterfunktion in einem Konstruktor:

public MyClass(int initialCount = 0, string name = "")

Beachten Sie, dass er ""anstelle von verwendet string.Empty.
Er kommentiert:

Sie werden [in einem Beispiel oben] feststellen, dass der zweite Konstruktor "" für den Standardwert im Parameter name angegeben hat und nicht den üblicheren string.Empty. Das liegt daran, dass string.Emptyes sich nicht um eine Kompilierungszeitkonstante handelt. Es ist eine statische Eigenschaft, die in der Zeichenfolgenklasse definiert ist. Da es sich nicht um eine Kompilierungskonstante handelt, können Sie sie nicht als Standardwert für einen Parameter verwenden.

Wenn wir die string.EmptyStatik nicht in allen Situationen verwenden können, macht das dann nicht den Zweck zunichte? Ich dachte, wir würden es verwenden, um sicherzugehen, dass wir ein systemunabhängiges Mittel haben, um auf die leere Zeichenfolge zu verweisen. Ist mein Verständnis falsch? Vielen Dank.

UPDATE
Nur ein nachfolgender Kommentar. Laut MSDN:

Jeder optionale Parameter hat einen Standardwert als Teil seiner Definition. Wenn für diesen Parameter kein Argument gesendet wird, wird der Standardwert verwendet. Standardwerte müssen Konstanten sein.

Dann können wir System.Environment.NewLineweder neu instanziierte Objekte noch als Standardwerte verwenden. Ich habe VS2010 noch nicht verwendet und das ist enttäuschend!

Mikeyg36
quelle
2
Mir sind keine Unterschiede zwischen der Darstellung leerer Zeichenfolgen auf verschiedenen Plattformen bekannt. Es ist nicht wie Newline.
Tom Cabanski
Richtig, ich habe das gedacht. Ist es dann nur so, dass es im Code besser aussieht?
Mikeyg36
1
Die CLR und nicht das 'System' ist der entscheidende Faktor dafür, ob "" eine leere Zeichenfolge ist oder nicht. Ich denke also, Sie können davon ausgehen, dass "" eine systemunabhängige Methode ist, um auf eine Zeichenfolge in einer kompatiblen CLR-Implementierung zu verweisen.
Chris Taylor
"systemunabhängig"? ähm, im Gegensatz zum systemspezifischen ""? (???)
Qwertie
Laut MSDN: Der Wert dieses Feldes ist die Zeichenfolge mit der Länge Null "". Dann hat es offensichtlich nichts mit Plattformunabhängigkeit zu tun, wie viele Leute betonen. Trotzdem scheinen die Leute nicht wirklich zu wissen, warum es verwendet werden sollte!
Mikeyg36

Antworten:

64

Ab dem C # 2.0-Compiler macht es String.Emptysowieso wenig Sinn , und tatsächlich ist es in vielen Fällen eine Pessimisierung, da der Compiler einige Verweise auf Inline einfügen kann, ""aber nicht dasselbe tun kann String.Empty.

In C # 1.1 war es nützlich zu vermeiden, viele unabhängige Objekte zu erstellen, die alle die leere Zeichenfolge enthalten, aber diese Zeiten sind vorbei. ""funktioniert gut.

Andy Mortimer
quelle
7
Selbst in .NET 1.1 würden nicht "viele" unabhängige Objekte erstellt. Ich kann mich nicht an die Details der Unterschiede zwischen 1.1 und 2.0 in dieser Hinsicht erinnern, aber es ist nicht so, dass das Internieren von String-Literalen erst in 2.0 eingeführt wurde.
Jon Skeet
Danke für die Klarstellung. Ich habe mich umgesehen und keine gute Zusammenfassung der Änderungen in C # 2.0 gefunden, obwohl ich sicher bin, dass ich zuvor eine gelesen habe. Ich habe eine StackOverflow-Antwort aus dem Jahr 2008 mit einigen Links zu weiteren technischen Informationen gefunden. stackoverflow.com/questions/151472/…
Andy Mortimer
1
Ich werde dies nicken, obwohl ich nicht gerne sage, dass es wenig Sinn macht, es zu bespannen. Leer, da ich es ziemlich stark benutze. Ich finde, es sieht einfach sauberer aus, obwohl das meine persönliche Meinung ist. Es gibt viele Stellen string.Empty kann nicht verwendet werden, und ich habe kein Problem mit "" in diesen Fällen
xximjasonxx
14
Ich habe festgestellt, dass es viel einfacher ist, eine leere Zeichenfolge schnell mit String.Empty zu identifizieren, als zweimal auf "" zu schauen, um sicherzustellen, dass kein Apostroph oder ähnliches darin versteckt ist. +1 für die Erklärung.
NotMe
11
+1 Chris. Auch in VS können Sie wirklich nicht nach Verwendungen von "" suchen (außer nach der Standardsuche, bei der auch jede Textübereinstimmung, einschließlich Kommentaren und Markups, wiederhergestellt wird). Sie können mit string.Empty nach codespezifischen Verwendungen suchen.
MutantNinjaCodeMonkey
53

Nichts hindert Sie daran, Ihre eigene Konstante für die leere Zeichenfolge zu definieren, wenn Sie sie wirklich als optionalen Parameterwert verwenden möchten:

const string String_Empty = "";

public static void PrintString(string s = String_Empty)
{
    Console.WriteLine(s);
}

[Abgesehen davon ist ein Grund, den String.EmptySie ""generell bevorzugen , der in den anderen Antworten nicht erwähnt wurde, dass es verschiedene Unicode-Zeichen (Joiner mit der Breite Null usw.) gibt, die für das bloße Auge praktisch unsichtbar sind. Etwas, das aussieht, ""ist also nicht unbedingt die leere Zeichenfolge, während String.EmptySie genau wissen, was Sie verwenden. Ich erkenne, dass dies keine häufige Fehlerquelle ist, aber es ist möglich.]

Matthew Strawbridge
quelle
2
Es gibt auch unsichtbare Bezeichner, sodass etwas, das wie String_Empty aussieht, nicht unbedingt vorhanden ist. Der Unicode-Standard enthält ein weitgehend ignoriertes Kapitel zu Sicherheitsaspekten.
Jim Balter
24

Aus der ursprünglichen Frage:

Ich dachte, wir würden es verwenden, um sicherzugehen, dass wir ein systemunabhängiges Mittel haben, um auf die leere Zeichenfolge zu verweisen.

Inwiefern kann die leere Zeichenfolge von System zu System variieren? Es ist immer eine Zeichenfolge ohne Zeichen! Ich hätte wirklich Angst, wenn ich jemals eine Implementierung gefunden hätte, bei der string.Empty == ""false zurückgegeben wurde :) Dies ist nicht dasselbe wie so etwas Environment.NewLine.

Aus dem Kopfgeldposten des Terroristen:

Ich möchte, dass String.Empty in der nächsten C # -Version als Standardparameter verwendet wird. : D.

Nun, das wird bestimmt nicht passieren.

Ich persönlich hätte mir auch einen ganz anderen Standardmechanismus gewünscht, aber die Funktionsweise optionaler Parameter war von Anfang an in .NET - und es bedeutet immer, eine Konstante in die Metadaten einzubetten, damit der aufrufende Code diese Konstante in den Aufruf kopieren kann Website, wenn kein entsprechendes Argument angegeben wird.

Mit ist string.Emptyes wirklich sinnlos - mit ""wird tun, was Sie wollen; Ist es so schmerzhaft, das String-Literal zu verwenden? (Ich benutze das Literal überall - ich benutze es nie string.Empty- aber das ist ein anderes Argument.)

Das ist , was mir über diese Frage überrascht - die Beschwerde dreht sich um etwas , was nicht der Fall ist Ursache ein echtes Problem tatsächlich. Dies ist wichtiger in Fällen, in denen der Standard zur Ausführungszeit berechnet werden soll, da er tatsächlich variieren kann. Ich könnte mir zum Beispiel Fälle vorstellen, in denen Sie eine Methode mit einem DateTimeParameter aufrufen möchten und standardmäßig "die aktuelle Zeit" verwenden möchten . Im Moment ist die einzige vage elegante Problemumgehung, die ich dafür kenne ,:

public void RecordTime(string message, DateTime? dateTime = null)
{
    var realDateTime = dateTime ?? DateTime.UtcNow;
}

... aber das ist nicht immer angemessen.

Abschließend:

  • Ich bezweifle sehr, dass dies jemals Teil von C # sein wird
  • Denn string.Emptyes ist sowieso sinnlos
  • Für andere Werte , die wirklich nicht den gleichen Wert haben immer, es ist wirklich kann ein Schmerz
Jon Skeet
quelle
Dies ist eigentlich eine gute Möglichkeit, das Problem zu beheben. Dasselbe kann verwendet werden, um andere geräteabhängige Variablen wie ... zu übertragen Environment.Newline. Das einzige, was in Ihrem Beispiel fehlt, ist die Überprüfung der Variablen auf null und das Zurückwerfen einer Ausnahme an den Entwickler, die ihm mitteilt, dass es zwar nullbar ist, es aber ist nicht akzeptiert. if(dateTime == null){ throw new ArgumentException("The dateTime parameter must be set. Nullable type used for device independent variable set.");}oder etwas ähnliches. Aber ich mag das wirklich! Irgendwelche anderen Vorbehalte, um es auf Ihre Weise zu tun?
MaxOvrdrv
@MaxOvrdrv: Sie möchten nicht, dass Null ein Fehler ist. Der springende Punkt ist, dass Sie einen Standard berechnen, wenn er Null ist. Die Einschränkung besteht darin, dass Null nicht als gültiger Wert an sich übergeben werden kann.
Jon Skeet
Da haben Sie vollkommen recht. Mein Fehler. - Und ja, das wäre die einzige wirkliche Einschränkung, nicht wahr ... das ist nicht so schlimm. Nochmals: Ich mag diese Lösung wirklich! :) Danke fürs posten! :)
MaxOvrdrv
7

Ich benutze nie string.Empty, ich kann den Sinn nicht erkennen. Vielleicht macht es es Leuten leichter, die wirklich neu in der Programmierung sind, aber ich bezweifle, dass es auch dafür nützlich ist.

Hans Olsson
quelle
2
Vielleicht verhindert es Verwirrung ""und " ", aber ich kann nicht sagen, dass " "das alles so häufig ist.
Greg
8
Ich würde jedem empfehlen, der den Unterschied zwischen diesen nicht erkennen kann, entweder eine bessere Brille oder eine geringere Auflösung des Bildschirms. Ich habe schlechtes Sehvermögen und kann mich nicht erinnern, jemals diesen Fehler gemacht zu haben (und ich muss mit viel Code arbeiten, der beides enthält).
Hans Olsson
2
string.Empty ist nützlich, um die genaue Absicht des Programmierers herauszufinden. "" sagt nichts über die Absicht aus, was wäre, wenn der Programmierer die Variable wie folgt initialisieren wollte "lol", aber vergessen würde ... in diesem Fall gibt es endlose Möglichkeiten und Zeichenfolgen, leer ist praktisch und macht einen besseren Job
nützlichBee
4

Ich denke, die Idee hinter string.Empty ist, dass es die Lesbarkeit verbessert. Es ist nicht wie bei Newline, wo es einen Unterschied gibt, wie es auf verschiedenen Plattformen dargestellt wird. Es ist schade, dass es nicht in einem Standardparameter verwendet werden kann. Es verursacht jedoch keine Probleme, wenn Sie zwischen Windows und etwas wie Mono unter Linux portieren.

Tom Cabanski
quelle
5
Ich denke, Sie haben wahrscheinlich Recht, dass der Punkt ist, dass einige Leute für String.Emptylesbarer halten. . . Ich persönlich finde das allerdings etwas verrückt. ""ist wahrscheinlich die häufigste Zeichenfolge, die es gibt, und jeder hat sie milliardenfach gesehen. Wie ist sie also unlesbar? String.Emptyist ungefähr so ​​nützlich, als ob es eine gäbe Int32.Zero.
Tim Goodman
3

Als FYI sieht es so aus, als ob die gleiche Einschränkung für Werte gilt, die an Attributkonstruktoren übergeben werden - sie müssen konstant sein. Da string.empty definiert ist als:

public static readonly string Empty

Anstelle einer tatsächlichen Konstante kann sie nicht verwendet werden.

Shawn Eavis
quelle
1

Ich benutze string.Emptynur zur besseren Lesbarkeit.

Wenn jemand anderes meinen Code später lesen / ändern muss, weiß er, dass ich nach einer leeren Zeichenfolge suchen oder diese festlegen wollte. Die Verwendung von just ""kann manchmal zu Fehlern und Verwirrung führen, da ich möglicherweise vergessen habe, die gewünschte Zeichenfolge dort einzufügen.

Beispielsweise:

if(someString == string.Empty)
{

}

vs.

if(someString == "")
{

}

Die erste ifAussage scheint mir einfach viel bewusster und lesbarer zu sein. Da dies jedoch nur eine Präferenz ist, sehe ich den Zugschlag wirklich nicht darin, ""stattdessen verwenden zu müssen string.Empty.

lukejkw
quelle
-2

Die vielleicht beste Lösung für dieses Problem ist eine Überlastung dieser Methode auf folgende Weise:

public static void PrintString() 
{ 
    PrintString(string.Empty);
}
lokum09
quelle
3
Wie ist das die obige Frage zu beantworten?
Pranav Singh
1
Wie hilft es bei Standardwerten für optionale Parameter?
Standardgebietsschema