Laden...

myString == "" oder string.Length == 0

Erstellt von Golo Roden vor 18 Jahren Letzter Beitrag vor 14 Jahren 25.006 Views
Information von herbivore vor 12 Jahren

Dies ist ein Thread, auf den aus der FAQ verwiesen wird. Bitte keine weitere Diskussion, sondern nur wichtige Ergänzungen und diese bitte knapp und präzise. Vielen Dank!

Abgeteilt von Mehre Bedingungen in einer IF-Verzweigung

Golo Roden Themenstarter:in
4.207 Beiträge seit 2003
vor 18 Jahren
myString == "" oder string.Length == 0

Hallo,

es wird im Allgemeinen empfohlen, statt auf einen Leerstring ("") zu prüfen, die Länge des Strings zu testen ... Tools wie FxCop kreiden einem entsprechende Vergleiche auf "" auch an.

Also statt if(myString == "") dann eben if(myString.Length == 0), da dies performanter ausgeführt wird.

Damit erübrigt sich auch die Frage, ob man "" oder string.Empty verwenden sollte.

Viele Grüße,

Golo

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo golohaas.de,

das Thema hatten wir schon ein paar Mal. 🙂

Die Laufzeit der Length-Variante ist nur geringfügig besser ist. Bei einer Million dieser Vergleiche spart man auf aktuellen Rechnern ca. 1/100s. Der Performancegewinn ist m.E. so gering, dass man ihn bei einer Entscheidung, auf welche Art man den Vergleich schreibt, guten Gewissens vernachlässigen kann. Ich würde daher immer die Variante verwenden, die mir lesbarer erscheint. Ich finde myString == "" am lesbarsten.

Is my string empty? Some C# performance metrics

herbivore

Suchhilfe: 1000 Worte, String.Empty, Lambda, String-Literal, String.IsNullOrEmpty, Int32.Zero, 0, Null, neutrale Element, neutrales Element, Addition, Konkatenation.

1.549 Beiträge seit 2004
vor 18 Jahren

Natürlich ist != "“ lesbarer aber
Folgender Code liefert ein Verhältnis von grob 1 zu 12


using System;

namespace string_test
{
	class MainClass
	{
		public static void Main(string[] args)
		{
			Console.WriteLine("Start");
			string s = "!";
			uint zähler = 0;
			int i = System.Environment.TickCount;
			i = System.Environment.TickCount;
			while(s != "" && zähler < uint.MaxValue)
			{
				zähler++;
			}
			Console.WriteLine((System.Environment.TickCount - i)/1000d);
			zähler = 0;
			
			i = System.Environment.TickCount;

			while(s.Length != 0 && zähler < uint.MaxValue)
			{
				zähler++;
			}
			Console.WriteLine((System.Environment.TickCount - i)/1000d);
		}
	}
}

Wir Arbeiten eigendlich nicht wir nehmen nur das geld

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo S.H.-Teichhof,

bei mir ist der Faktor zwischen den Schleifenlaufzeiten ungefähr vier. Bereinigt um den Overhead der Schleife ist der Faktor sogar ungefähr sechs bis sieben. Aber was ändert das an meiner Aussage? Ich habe mich ja auf den absoluten Performance-Gewinn bezogen.

herbivore

PS: Um das vielleicht noch etwas zu unterfüttern: Wenn du eine Datei von einer Million Zeilen einlesen und jede Zeile mit strLine == "" statt str.Length == 0 prüfen würdest, verliert du gerade mal Zeit in der Größenordnung von 1/100s.

Q
992 Beiträge seit 2005
vor 18 Jahren

Ich denke, dass String.Empty am saubersten ist.

ich mache auch immer

String mystring = String.Empty wenn ich einen neuen leeren String haben will!

N
4.644 Beiträge seit 2004
vor 18 Jahren

Weshalb sollte das am saubersten sein. Es liest sich vielleicht für den ein oder anderen besser.

Q
992 Beiträge seit 2005
vor 18 Jahren

Genauso war es auch gedacht. Ich denke, dass sich das am Besten liest!
Aber das ist ein subjektives Empfinden!

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Quallo,

das wundert mich. Ich finde String.Empty genauso überflüssig, wie Int32.Zero (was es ja auch nicht gibt).

herbivore

N
4.644 Beiträge seit 2004
vor 18 Jahren

Genauso war es auch gedacht.

Dann musst Du es auch so schreiben. So kannst Du Dir später die '!' sparen. 😉

Q
992 Beiträge seit 2005
vor 18 Jahren

Naja, String.Empty und Int32.Zero ist ja noch ein wenig was anderes, obwohl schon sehr ähnlich. Aber ich glaube die Diskussion darüber wird ganz schnell philosophisch.

Am besten würde mir eine schnelle InstanzMethode( zum Beispiel bool StringInstanz.IsEmpty() ) gefallen.

@Noodles: Ich dachte mit ein bisschen Nachdenken kommt man auf das was ich meinte g!

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Quallo,

unter .NET 2.0 gibt es zumindest String.IsNullOrEmpty.

herbivore

Q
992 Beiträge seit 2005
vor 18 Jahren

Ist doch schon mal ein guter Anfang. Bin dann mal auf die Performance gespannt.

Grüße Christoph

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Quallo,

die Performance liegt wie zu erwarten zwischen s.Length == 0 und s == "" und spielt damit absolut gesehen ebenfalls keine Rolle (<1/100s bei einer Mio Aufrufen).

Allerding ist IsNullOrEmpty eine statische Methode. Man muss also schreiben: String.IsNullOrEmpty (s). Keine Ahnung was der Quatsch soll.

Davon abgesehen fände/finde ich (nach der geleichen Überlegung wie bei String.Empty/Int32.Zero) String.IsEmpty ebenso überflüssig wie Int32.IsZero. 🙂

herbivore

Q
992 Beiträge seit 2005
vor 18 Jahren

Wie schon gesagt, das geht wohl mehr in den Bereich der Philosophie!
Ich finde, dass 0 eine Zahl wie jede andere ist(ich weiß, mathematisch gesehen ist es nicht so, da haben Leute schon Bücher drüber geschrieben) und ein leerer String irgendwie ein Sonderfall ist.

Aber wenn ich die Wahl hätte, was in .Net verbessert werden könnte, dann wäre String.IsEmpty wohl auch das letzte, was ich wählen würde g

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Quallo,

wenn wir schon am Philosphieren sind: 0 ist das neutrale Element der Addition und "" ist das neutrale Element der Konkatenation. Das das ziemlich ähnliche Operationen sind, sieht man schon daran, dass in .NET für beide derselbe Operator gewählt wurde. Darüberhinaus sind beides Literale. Warum man bei dieser (auch strukturellen) Ähnlichkeit für das eine Literal ("") eine zusätzliche Konstantendefinition (String.Empty) braucht, erschließt sich mir nicht. Aber vielleicht gibt es ja einen Philosophen hier, der das aufklären kann. 🙂

herbivore

1.549 Beiträge seit 2004
vor 18 Jahren

Um es voraus zu sagen ich bin auch dafür != "" einzusetzen (find ich einfach besser zu lesen)

Aber ich finde es ist schon ein unterschied ob "" oder 0 da steht weil "" ist ja einfach „leer“ 0 ist aber etwas den in der Mathematik gibt es ja eben Kein Ergebnis oder es gibt eines z.B 0 oder 1 usw..

Wir Arbeiten eigendlich nicht wir nehmen nur das geld

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo S.H.-Teichhof,

oh, das war wieder echt schwer zu lesen, so ohne Satzzeichen. 🙂 Aber ich glaub, jetzt habe ich es.

Ich hatte ja gerade argumentiert, dass es mathematisch kein wesentlichen Unterschied zwischen 0 und "" gibt.

"" ist nicht einfach leer, sondern genau so ein Ergebnis, wie 0 oder 1. Wenn ein Methode einen Rückgabewert hat, muss sie auch etwas zurückliefern, egal ob es der Rückgabetyp Int32 oder String ist. Als kein Ergebnis könnte man hier eine Exception ansehen. Aber auch hier gibt es dann wieder keinen Unterschied zwischen Rückgabetyp Int32 und String. Jedenfalls ist "" etwas anderes als kein Ergebnis.

Und anderesherum: In Bezug auf die Addition/Konkatenation bedeutet 0 im gleichen Maß nichts wie "".

herbivore

1.549 Beiträge seit 2004
vor 18 Jahren

Ok meine Zeichen Setzung ist wirklich noch nicht ganz super =), aber immerhin sind die Rechtschreibfehler fast weg.
Aber um dir zu antworten: Ich habe vergessen zu schreiben das es ein Rein Subjektiver Eindruck ist, Objektiv hast du natürlich recht. Aber versuch doch mal einem Lehrer ein Leeres Blatt als Hausaufgabe abzugeben und im dann zu erklären das ein Leeres Blatt auch ein Ergebnis ist =).

Wir Arbeiten eigendlich nicht wir nehmen nur das geld

Q
992 Beiträge seit 2005
vor 18 Jahren

Bei Zahlen hat man einen Wert für das Nichts, bei Zeichenketten stellt man das Nichts nur durch "" dar, hat aber kein spezielles Zeichen dafür, bzw. das Zeichen ist ein nicht vorhandenes Zeichen. Deswegen auch die Kostante String.Empty. Sie Steht für eine leere Zeichenkette, sowie die 0 für etwas nicht vorhandenes bei den Zahlen steht(ich weiß, dass das eine sehr sehr einfache Vorstellung ist). Das oft benutze "" stellt nur eine Beschreibung der leeren Zeichenkette dar, ist aber kein leere Zeichenkette.

Tja, du hast mich zum philosophieren eingeladen Herbivore g.
Wahrscheinlich kommt als Nächstes das Ganze eine Ebene tiefer, wie es sich für den Compiler darstellt.

Grüße Christoph

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Quallo,

ok, du hast mich überzeugt! Was die Mathematik (bzw. theoretische Informatik) anbelangt. Da hat man tatsächlich ein extra Zeichen für die leere Zeichenfolge, nämlich das keine Lambda.

Was C# angeht, würde ich weiterhin widersprechen. "" ist die leere Zeichenkette, genauso wie 0 Null ist. Genauer: "" ist das Literal, dass die leere Zeichenkette repräsentiert, genauso wie 0 das Literal ist, das die Null repräsentiert. Da gibt es für mich (in C#) keinen qualitativen Unterschied.

herbivore

Q
992 Beiträge seit 2005
vor 18 Jahren

Aber nur wenn man "" als Sonderfall betrachtet. Ich sehe es eher so, dass man zwischen die "-Zeichen den Inhalt des gewünschten Strings schreibt. Wenn man da nichts reintut, dann bekommt man als Ergebnis einen leeren String.
Das bedeutet aber nicht, dass "" das Zeichen für eine leere Zeichenkette ist. g
Haarspalterei das Ganze. Naja, meine persönliche Vorliebe bleibt String.Empty. Wobei, als ich das noch nicht kannte, da habe ich auch immer "" benutzt!

Grüße Christoph

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Quallo,

in C# gehören aber die Anführungsstrich zu einem String-Literal dazu. Also steht man gar nicht vor dem Problem etwas nicht vorhandenes nicht erkennen zu können. Also steht "" durchaus für die leere Zeichenkette. Daher würde ich nicht gelten lassen, dass man aus dieser Überlegung heraus String.Empty braucht.

Aber - und in soweit hat mich unsere Haarspalterei schon weitergebracht - ich erkenne jetzt an, dass String.Empty seine Berechtigung hat, als Entsprechung von Lambda in der Mathematik. Für die Null braucht man in der Mathematik kein anderes Symbol als die Null. Für den leeren String braucht man ein anderes Symbol als den leeren String (den man ja hier nicht sehen würde), nämlich Lambda. Also führt man dafür in C# String.Empty ein.

Ich kann also das vorhanden sein von String.Empty aus einer systematische Überlegung heraus verstehen. Da jedoch durch die String-Literalschreibweise von C# der leere String wieder sichtbar wird, halte ich die praktische Verwendung von String.Empty jedoch nicht für sinnvoll, wobei ich anerkenne, dass es keine zwingenden Gründe gibt, so dass es letzten Ende Geschmackssache bleibt.

herbivore

4.221 Beiträge seit 2005
vor 18 Jahren

Allerding ist IsNullOrEmpty eine statische Methode. Man muss also schreiben: String.IsNullOrEmpty (s). Keine Ahnung was der Quatsch soll.

Na dann lass den folgenden Code mal laufen

string s=null;
if (s.IsNullOrEmpty())
{
 
}

CRASH !

Hoffe jetzt ist es dir klar 😁

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Programmierhans,

überzeugt 🙂 Typischer Fall, von "habe ich wohl nicht zu ende gedacht". Und das in einer philosophischen Diskussion. pein

herbivore

Q
992 Beiträge seit 2005
vor 18 Jahren

Ist mir auch kein Stück aufgefallen.
Na klar, wie soll das gehen eine Methode einer Null-Instanz aufzurufen.

4.221 Beiträge seit 2005
vor 18 Jahren

Ist mir auch kein Stück aufgefallen.

Mir ist es regelrecht in's Auge gestochen.... kommt wohl vom regelmässigen Debuggen von Code anderer Leute... da ist jedes Objekt suspekt welches vor der Verwendung nicht auf null geprüft wird...

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

O
778 Beiträge seit 2007
vor 17 Jahren

Aber um mit der Diskussion mit "" und String.Empty ein Ende zu setzen:
Es gibt einen unterschied, der liegt aber nicht in der Performance, sondern im Speicherverbrauch. String ist irgendwo auch ein stinknormales Objekt mit stinknormalen Referenzeigenschaften, d.h.,

String s = "";

erzeugt eine neue String-Instanz und referenziert diese, während

String s = String.Empty;

eine vorhandene Instanz referenziert.

Da Strings sowieso Immutable sind, gibt es also schlicht nur Vorteile (performancemäßig) von String.Empty
Aber: Der Compiler ist ja auch nicht doof, sodass alle Strings erstmal gepoolt werden, was folgendes verursacht:


String s1 = "";
String s2 = "";
String s3 = String.Empty;
Object.ReferenceEquals(s1,s2) //True
Object.ReferenceEquals(s1,s3) //False
Object.ReferenceEquals(s1,String.Empty) //False
Object.ReferenceEquals(s3,String.Empty) //True

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo onlinegurke,

Aber um mit der Diskussion mit "" und String.Empty ein Ende zu setzen:

damit hast du sie aber leider im Gegenteil wieder angefacht. 🙂 Es gibt keine (messbaren) Performancevorteile von String.Empty, weil für "" - wie du am Ende richtig sagst - nur ein einziges zusätzliches Objekt angelegt wird, das zudem quasi keinen zusätzlichen Speicher verbraucht. Das kostet auch deshalb nichts, weil das nötige Pooling vom Compiler und nicht zur Laufzeit vorgenommen wird. (Natürlich kann man auch zur Laufzeit auf den Pool zugreifen, aber das spielt hier keine Rolle). Es ist also wie schon weiter oben gesagt: die Lesbarkeit entscheidet und nicht die Performance!

herbivore

O
778 Beiträge seit 2007
vor 17 Jahren

Ja, aber es gibt einen Performancegewinn > 0 und als Mathematiker bin ich glücklich damit, auch wenn der so im Bereich von Epsilon liegen dürfte. 🙂

1.665 Beiträge seit 2006
vor 17 Jahren

Als Informatiker hat dich das nicht zu interessieren 😉
Ganz allgemein gesagt halte ich das Thema mittlerweile auch für Haarspalterei 🙂

M
164 Beiträge seit 2009
vor 14 Jahren

(Hat mich einfach interessiert (auch wenns nur Haarspalterei ist))

Hab mal für 3 Varianten den IL Code verglichen und ich kopiere euch die Zeilen rein, die verschieden sind (alle anderen sind der Übersichtlichkeit her gelöscht)

//if (s == "")
IL_0008:  ldstr      ""
IL_000d:  call       bool [mscorlib]System.String::op_Equality(string,
                                                     string)

//if (s.Length == 0)
IL_0008:  callvirt   instance int32 [mscorlib]System.String::get_Length()
IL_000e:  ceq
IL_0010:  ldc.i4.0

//if (String.IsNullOrEmpty(s))
IL_0008:  call       bool [mscorlib]System.String::IsNullOrEmpty(string)

Kann man die Threadfrage überhaupt beantworten (ausser mit Laufzeittests), wenn man die genaue Implementierung der mscorlib nicht kennt?

Ich denke, die String::get_Length() Funktion dürfte am effizientesten sein, da ja eigentlich ein Startpointer übergeben wird und nur die Bytes gezählt werden, bis das Terminate-Zeichen (\0) kommt.

Noch eine Offtopic-Frage am Rande: Verwendet ihr i; oder i;?

In ASCII-C soll man ja i; verwenden, da der Compiler somit eine Assembler-Anweisung weniger schreiben muss (bei i muss die alte Variable zuerst ausgelagert werden usw..)

6.911 Beiträge seit 2009
vor 14 Jahren

Hallo,

Kann man die Threadfrage überhaupt beantworten (ausser mit Laufzeittests), wenn man die genaue Implementierung der mscorlib nicht kennt?

Es müsste auch bekannt sein wieviel Zyklen eine IL-Anweisung tatsächlich braucht. Da dies nicht der Fall ist gehts nur über Vergleiche.

Noch eine Offtopic-Frage am Rande: Verwendet ihr i; oder i;?

Kommt darauf an wann i inkrementiert werden soll. Vorher oder nachher. Danach richtet sich das.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

6.862 Beiträge seit 2003
vor 14 Jahren

In ASCII-C soll man ja i; verwenden, da der Compiler somit eine Assembler-Anweisung weniger schreiben muss (bei i muss die alte Variable zuerst ausgelagert werden usw..)

Solche Kleinigkeiten sind in .Net vollkommen bedeutungslos. Klar, im Endeffekt unterschiedet sich der Code in der gleichen Art wie bei C, aber was Performance angeht, hat man in .Net an ganz anderen Stellen zu kämpfen.

Ich denke, die String::get_Length() Funktion dürfte am effizientesten sein, da ja eigentlich ein Startpointer übergeben wird und nur die Bytes gezählt werden, bis das Terminate-Zeichen (\0) kommt. Da bist du zu sehr in deiner C Welt 😃In .Net sind Strings nicht nullterminiert. Du kannst problemlos Strings erstellen mit mittendrin \0 und trotzdem werden die Stringfunktionen richtig funktionieren. Im Prinzip wird das Property nur auf nen Feld zugreifen was beim Erzeugen des Strings einmalig gesetzt wird. Danach kann sich der String eh nicht mehr ändern. Daher macht ein Durchzählen weniger Sinn. (Aber durch die erlaubte \0 kann man nen paar lustige Effekte sehen wenn man z.B. nen String ausgeben möchte mit Windows Forms. Da liegen in den allermeisten Fällen ja einfache WinApi Funktionen hinter und die kümmern sich dann wiederum sehr wohl um das \0 Zeichen und schneiden da den String ab.

Baka wa shinanakya naoranai.

Mein XING Profil.

6.911 Beiträge seit 2009
vor 14 Jahren

Hallo talla,

Solche Kleinigkeiten sind in .Net vollkommen bedeutungslos.

dem kann ich nicht ganz zustimmen. Bei einer Zuweisung unterscheidet sich der Wert allenfalls um genau 1 und das kann nicht bedeutungslos sein.
Laufzeittechnisch hast du aber recht.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

M
164 Beiträge seit 2009
vor 14 Jahren

Bei einer Zuweisung unterscheidet sich der Wert allenfalls um genau 1 und das kann nicht bedeutungslos sein.

Ich habe die Inkrementierung per se gemeint - dass es bei einer Zuweisung draufankommt, ob vor oder nach der zuweisung inkrementiert wird, weiss ich (und hab ich eigentlich als Grundwissen vorausgesetzt)

Ich denke, wenn einer eine schnelle Konsolenanweisung schreiben will, die Daten ausliest, verarbeitet und wieder ausspuckt, kann man mit kleinen Kniffs und Tricks doch noch ein paar Prozent Geschwindigkeit rausholen.

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo martinO,

Ich denke, wenn einer eine schnelle Konsolenanweisung schreiben will, die Daten ausliest, verarbeitet und wieder ausspuckt, kann man mit kleinen Kniffs und Tricks doch noch ein paar Prozent Geschwindigkeit rausholen.

unwahrscheinlich. Die durch Mikrooptimierungen zu erzielenden Einsparungen sind heutzutage in der Regel vollkommen unerheblich. Generell gilt: "premature optimization is the root of all evil". Aber jetzt bitte auch Schluss mit offtopic.

herbivore

0
767 Beiträge seit 2005
vor 14 Jahren

Hallo,

das ist zwar eine uralte Quote, aber dennoch:

Ich finde String.Empty genauso überflüssig, wie Int32.Zero (was es ja auch nicht gibt).


class X
{
  String s1; // s1 = null
  String s2 = String.Empty; // s2 = "";

  Int32 i1; // i1 = 0;
  Int32 i2 = Int32.Zero; // i2 = 0
}

Fehlermeldung:
error CS0117: "int" enthält keine Definition für "Zero".

string.Empty entspricht nicht dem Default Value für strings, welcher null ist.
Wahrscheinlich wurde es deshalb eingeführt.

loop:
btst #6,$bfe001
bne.s loop
rts

6.862 Beiträge seit 2003
vor 14 Jahren

Hallo,

Die Aussage

string.Empty entspricht nicht dem Default Value für strings, welcher null ist. ist so nicht richtig.

s1 und s2 sind in deinem Beispiel ja keine Stringobjekte, sondern nur Referenzen die auf Stringobjekte zeigen können. Referenzen werden immer mit null initialisiert, was soll man auch anderes machen. Einfach den Defaultkonstruktor der jeweiligen Klasse aufrufen geht ja auch nicht, da man nicht vorhersehen kann was für Auswirkungen es hat und ob es den überhaupt gibt.

Da Strings sich aber wie Werttypen verhalten, ist es natürlich nur praktisch auch nen Defaultwert zu haben - und das ist String.Empty welches vom statischen String Konstruktor auf "" initialisiert wird. Man muss also nicht new String() aufrufen um nen Defaultobjekt zu haben.

Wertetypen werden ja einfach mit 0-Bytes initialisiert - das ergibt dann halt auch den numerischen Wert 0 bei int.

Baka wa shinanakya naoranai.

Mein XING Profil.

S
8.746 Beiträge seit 2005
vor 14 Jahren

Der Unterschied zwischen string.Empty und "" offenbart sich in diesem Fall aus der Distanz. Tretet mal einen Meter vom Monitor zurück (oder setzt die Brille ab).

string.Empty "" "'" " " Wer da den Unterschied nicht erkennt, der hat entweder Adleraugen oder eine 24-Punkt-Schrift eingestellt.