Wie mache ich ToString für ein möglicherweise null Objekt?


97

Gibt es eine einfache Möglichkeit, Folgendes zu tun:

String s = myObj == null ? "" : myObj.ToString();

Ich weiß, dass ich Folgendes tun kann, aber ich betrachte es wirklich als Hack:

String s = "" + myObj;

Es wäre großartig, wenn Convert.ToString () eine ordnungsgemäße Überladung dafür hätte.


3
Ich sehe nichts falsch mit dem ersten. Wenn Sie den zweiten als Hack betrachten, schreiben Sie am besten einfach eine Dienstprogrammfunktion, die die Nullprüfung durchführt.
Nick Larsen

PLZ können Sie genauer über Ihre Frage sein
FosterZ

3
string.Format ("{0}", myObj) akzeptiert Nullwerte.
Holstebroe

3
Mit C # 6.0 können wir jetzt nullbedingte Operatoren wie theText? .ToString () oder theText? .Trim ()
Santosh

2
Per diese Antwort Convert.ToString() macht genau das erste, was Sie darunter geschrieben haben.
Drzaus

Antworten:


175

C # 6.0 Bearbeiten:

Mit C # 6.0 können wir jetzt eine prägnante, gussfreie Version der Originalmethode haben:

string s = myObj?.ToString() ?? "";

Oder sogar mit Interpolation:

string s = $"{myObj}";

Ursprüngliche Antwort:

String s = (myObj ?? String.Empty).ToString();

oder

String s = (myObjc ?? "").ToString()

noch prägnanter sein.

Wie bereits erwähnt, benötigen Sie leider häufig eine Besetzung auf beiden Seiten, damit dies mit Nicht-String- oder Objekttypen funktioniert:

String s = (myObjc ?? (Object)"").ToString()
String s = ((Object)myObjc ?? "").ToString()

Daher ist die Besetzung, obwohl sie vielleicht elegant erscheint, fast immer notwendig und in der Praxis nicht so prägnant.

Wie an anderer Stelle vorgeschlagen, empfehle ich möglicherweise die Verwendung einer Erweiterungsmethode, um dies sauberer zu machen:

public static string ToStringNullSafe(this object value)
{
    return (value ?? string.Empty).ToString();
}

Wird dies kompiliert? Überprüft der Koaleszenzoperator nicht die Typen?
Nick Larsen

1
Es funktioniert, da (Objekt ?? Zeichenfolge) Objekt zurückgibt, da Koaleszenz den am wenigsten verbreiteten Typ verwendet. Ich denke jedoch, dass dies für Schnittstellen nicht funktioniert, da nicht entschieden werden kann, welche Schnittstelle ausgewählt werden soll (da mehrere Schnittstellen pro Klasse zulässig sind).
Codymanix

1
Nicht wirklich die Lösung, auf die ich gehofft hatte, aber ich werde sie akzeptieren
Codymanix

4
Downvoting als Objektbesetzung ist furchtbar hässlich und beinhaltet Boxen.
Steinar

1
Die erste Option zu c # 6 ist sehr elegant
Alexandre N.

40
string.Format("{0}", myObj);

string.Format formatiert null als leere Zeichenfolge und ruft ToString () für Nicht-Null-Objekte auf. So wie ich es verstehe, haben Sie danach gesucht.


3
Ich persönlich mag das nicht. Der Code ist möglicherweise unwesentlich kürzer als String s = myObj == null? "": myObj.ToString (), aber Sie verbergen die Gründe für Ihre Methode vollständig.
AGuyCalledGerald

Zugegeben, dies ist eine Mikrooptimierung, die jedoch etwa fünfmal länger dauert als nur "" + myObj. Aber ich habe gelesen, dass zusätzliche Zeichenfolgen erstellt werden. str.Concat(myObj)scheint gut zu funktionieren und ist "noch schneller".
Drzaus

17

Es wäre großartig, wenn Convert.ToString () eine ordnungsgemäße Überladung dafür hätte.

Es gibt ein Convert.ToString(Object value).Net 2.0 (ca. 5 Jahre bevor dieses Q gefragt wurde), das genau das zu tun scheint, was Sie wollen:

http://msdn.microsoft.com/en-us/library/astxcyeh(v=vs.80).aspx

Vermisse / interpretiere ich hier etwas wirklich Offensichtliches?


1
Das tust du nicht. Warum einfach, wenn es kompliziert sein kann :)
alex.peter

13

Mit einer Erweiterungsmethode können Sie Folgendes erreichen:

public static class Extension
{
    public static string ToStringOrEmpty(this Object value)
    {
        return value == null ? "" : value.ToString();
    }
}

Folgendes würde nichts auf den Bildschirm schreiben und keine Ausnahme auslösen:

        string value = null;

        Console.WriteLine(value.ToStringOrEmpty());

Lassen Erweiterungsmethodenaufrufe die übliche Prüfung auf Nullen aus ...?
Matti Virkkunen

2
Es fügt hinzu, dass Sie nicht "{0}" eingeben müssen und dass Sie einen Methodennamen auswählen können, der beschreibt, was Sie tun. Dies ist besonders nützlich, wenn Sie dies oft tun. Sie können sogar die Methode ToStringOrEmptyWhenNull benennen.
Pieter van Ginkel

2
Wenn das OP dies für string s = "" + myObj;hackisch hält, sollte der Aufruf einer Funktion für ein Nullobjekt in dasselbe Boot fallen. Ich würde dies ablehnen, aber es löst das vorliegende Problem, ich bin nur nicht einverstanden mit der Verwendung. Null-Objekte sollten NullReferenceExceptionauch in Erweiterungsmethoden ausgelöst werden.
Nick Larsen

2
@ NickLarsen: Ich stimme Ihnen in den meisten Fällen zu, aber manchmal möchten Sie nur die Bequemlichkeit eines einfachen Methodenaufrufs. Der Methodenname sollte Ihnen einen Hinweis geben, dass Nullreferenzen in Ordnung sind, wie beim Vorschlag für ToStringOrEmptyWhenNull.
Jordão

3
Erweiterungsmethoden werfen nicht den "ersten" Parameter (den thisParameter), da es sich nur um syntaktischen Zucker handelt. Das heißt x.SomeExtensionMethod()ist syntaktischer Zucker für SomeStaticClass.SomeExtensionMethod(x);Wenn also xwird nullman kein Verfahren auf einem versucht aufzurufen nullObjekt , sondern ein vorübergehendes nullObjekt zu einer statischen Methode. Wenn und nur wenn diese Methode nach einem nullParameter sucht und bei Auftreten eines solchen auslöst, wird eine Erweiterungsmethode für einen Objektwurf "aufgerufen" null.
Jason

7

Ich bin damit nicht einverstanden:

String s = myObj == null ? "" : myObj.ToString();

ist in keiner Weise ein Hack. Ich denke, es ist ein gutes Beispiel für klaren Code. Es ist absolut offensichtlich, was Sie erreichen möchten und dass Sie null erwarten.

AKTUALISIEREN:

Ich sehe jetzt, dass Sie nicht gesagt haben, dass dies ein Hack war. Aber es ist in der Frage impliziert, dass Sie denken, dass dieser Weg nicht der richtige ist. In meinen Augen ist es definitiv die klarste Lösung.


Er sagte nicht, dass diese Methode Hack war. Tatsächlich sagte er nicht, was daran falsch war, außer vielleicht, dass es nicht einfach war. Ich glaube nicht, dass an dieser Methode etwas falsch ist. +1 weil ich es so machen würde.
Mark Byers

Ich stimme OP zu ... es gibt bereits einen Null-Koaleszenz-Operator in c # - siehe meinen Beitrag unten.
Andrew Hanlon

Ich denke, der Null-Koaleszenz-Operator ist in diesem Fall etwas weniger klar, aber ich würde das genauso gut verwenden.
Steinar

@Pieter Fair genug. Aber es tut. Die Frage lautet: "Gibt es eine einfache Möglichkeit, Folgendes zu tun: ...". Genau so ist es einfach!
Steinar

Ich habe nie gesagt, dass diese Methode ein Hack ist. Bitte lesen Sie meine Frage noch einmal. Ich vermisse nur eine kleine Funktion im Framework, die diese Funktionalität hat.
Codymanix

4
string s = String.Concat(myObj);

Ich denke, dies wäre der kürzeste Weg und hätte auch einen vernachlässigbaren Leistungsaufwand. Denken Sie daran, dass es für den Leser des Codes nicht ganz klar ist, was die Absicht ist.


2
Dies ist die explizite Form von "" + myObj, aber noch schlimmer, wenn man sagt, was hier vor sich geht. Interessant trotzdem.
Codymanix

@codymanix Ich denke nicht, dass es das gleiche ist - macht Concattatsächlich eine Nullprüfung darunter und gibt zurück string.Emptyoder arg0.ToString(), was etwas performanter zu sein scheint (ich meine, wir reden hier über ms).
Drzaus

2

Eigentlich habe ich nicht verstanden, was du machen willst. Soweit ich weiß, können Sie diesen Code auch so schreiben. Fragen Sie das oder nicht? Kannst du mehr erklären?

string s = string.Empty;
    if(!string.IsNullOrEmpty(myObj))
    {
    s = myObj.ToString();
    }

Sicher kann ich es so schreiben, aber ich möchte einen einfachen kleinen Funktionsaufruf. Ich habe mich gefragt, warum es in der .NET BCL
codymanix

Benötigen Sie wirklich eine Funktion, während wir die IsNullOrEmpty () -Methode haben?
Serkan Hekimoglu

In diesem Sinne wollte ich immer, dass der Koaleszenzoperator als nächstes fehlschlägt, wenn er eine Nullreferenz in Ihrem fließenden Ausdruck trifft, aber ich verstehe vollkommen, warum das eine schreckliche Idee ist. Ein Override, mit dem Sie das tun können, wäre auch schön.
Nick Larsen

1
string s = string.IsNullOrEmpty(myObj) ? string.Empty : myObj.ToString();
Nick Larsen

2

Ich könnte für meine Antwort verprügelt werden, aber hier geht es trotzdem:

Ich würde einfach schreiben

Zeichenfolge s = "" if (myObj! = null) {x = myObj.toString (); }}

Gibt es eine Leistungsauszahlung für die Verwendung des ternären Operators? Ich weiß es nicht genau.

Und natürlich können Sie, wie oben erwähnt, dieses Verhalten in eine Methode wie safeString (myObj) einfügen, die die Wiederverwendung ermöglicht.


OMG Wenn das Objekt null ist, rufen Sie dann ToString () auf.
Codymanix

Komm schon, das ist ein Tippfehler. Ich habe das erste = durch ersetzt! um es richtig zu machen. Aber du wirst mich wirklich wegen eines Tippfehlers -1?
Jaydel

2

Ich hatte das gleiche Problem und löste es, indem ich das Objekt einfach in einen String umwandelte. Dies funktioniert auch für Nullobjekte, da Zeichenfolgen Nullen sein können. Sofern Sie absolut keine Nullzeichenfolge haben möchten, sollte dies einwandfrei funktionieren:

string myStr = (string)myObj; // string in a object disguise or a null

Kürzeste und beste Lösung. (Obj1 ?? "") .ToString () wirft tatsächlich zuerst auch Obj1 als String :)
TPAKTOPA

2

Einige (Geschwindigkeits-) Leistungstests, die die verschiedenen Optionen zusammenfassen, nicht dass es wirklich darauf ankommt #Mikrooptimierung (unter Verwendung einer Linqpad-Erweiterung )

Optionen

void Main()
{
    object objValue = null;
    test(objValue);
    string strValue = null;
    test(strValue);
}

// Define other methods and classes here
void test(string value) {
    new Perf<string> {
        { "coallesce", n => (value ?? string.Empty).ToString() },
        { "nullcheck", n => value == null ? string.Empty : value.ToString() },
        { "str.Format", n => string.Format("{0}", value) },
        { "str.Concat", n => string.Concat(value) },
        { "string +", n => "" + value },
        { "Convert", n => Convert.ToString(value) },
    }.Vs();
}

void test(object value) {
    new Perf<string> {
        { "coallesce", n => (value ?? string.Empty).ToString() },
        { "nullcheck", n => value == null ? string.Empty : value.ToString() },
        { "str.Format", n => string.Format("{0}", value) },
        { "str.Concat", n => string.Concat(value) },
        { "string +", n => "" + value },
        { "Convert", n => Convert.ToString(value) },
    }.Vs();
}

Es ist wahrscheinlich wichtig darauf hinzuweisen, dass Convert.ToString(...)eine Nullzeichenfolge beibehalten wird.

Ergebnisse

Objekt

  • Nullcheck 1.00x 1221 verstrichene Ticks (0.1221 ms) [in 10K Wiederholungen, 1.221E-05 ms pro]
  • Coallesce 1,14x 1387 verstrichene Ticks (0,1387 ms) [in 10K-Wiederholungen 1,387E-05 ms pro]
  • Zeichenfolge + 1,16 x 1415 verstrichene Ticks (0,1415 ms) [in 10K-Wiederholungen 1,415E-05 ms pro]
  • str.Concat 1.16x 1420 Ticks verstrichen (0.142 ms) [in 10K Wiederholungen, 1.42E-05 ms pro]
  • Konvertierte 1,58x 1931 abgelaufene Ticks (0,1931 ms) [in 10K-Wiederholungen 1,931E-05 ms pro]
  • str.Format 5.45x 6655 Ticks verstrichen (0.6655 ms) [in 10K Wiederholungen, 6.655E-05 ms pro]

String

  • Nullcheck 1.00x 1190 verstrichene Ticks (0.119 ms) [in 10K Wiederholungen, 1.19E-05 ms pro]
  • Konvertieren Sie die verstrichenen 1,01 x 1200 Ticks (0,12 ms) [in 10K-Wiederholungen 1,2E-05 ms pro]
  • Zeichenfolge + 1,04 x 1239 verstrichene Ticks (0,1239 ms) [in 10K-Wiederholungen 1,239E-05 ms pro]
  • Coallesce 1,20x 1423 Ticks verstrichen (0,1423 ms) [in 10K Wiederholungen 1,423E-05 ms pro]
  • str.Concat 4.57x 5444 Ticks verstrichen (0.5444 ms) [in 10K Wiederholungen, 5.444E-05 ms pro]
  • str.Format 5.67x 6750 verstrichene Ticks (0.675 ms) [in 10K-Wiederholungen, 6.75E-05 ms pro]

1

Holstebroes Kommentar wäre Ihre beste Antwort:

string s = string.Format("{0}", myObj);

Wenn myObjnull ist, platziert Format dort einen Wert für eine leere Zeichenfolge.

Es erfüllt auch Ihre einzeiligen Anforderungen und ist leicht zu lesen.


Ja, aber der Code ist nicht klar. Wie viele Ihrer Entwicklerkollegen werden wissen, was Sie erreichen möchten?
AGuyCalledGerald

0

Obwohl dies eine alte Frage ist und das OP nach C # gefragt hat, möchte ich eine VB.Net-Lösung für diejenigen freigeben, die eher mit VB.Net als mit C # arbeiten:

Dim myObj As Object = Nothing
Dim s As String = If(myObj, "").ToString()

myObj = 42
s = If(myObj, "").ToString()

Leider lässt VB.Net den? -Operator nach einer Variablen nicht zu, sodass myObj? .ToString nicht gültig ist (zumindest nicht in .Net 4.5, das ich zum Testen der Lösung verwendet habe). Stattdessen verwende ich das If, um eine leere Zeichenfolge zurückzugeben, falls myObj nichts ist. Der erste Tostring-Aufruf gibt also eine leere Zeichenfolge zurück, während der zweite (wobei myObj nicht Nothing ist) "42" zurückgibt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.