Come fare ToString per un oggetto possibilmente nullo?


97

C'è un modo semplice per fare quanto segue:

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

So di poter fare quanto segue, ma lo considero davvero un hack:

String s = "" + myObj;

Sarebbe fantastico se Convert.ToString () avesse un sovraccarico adeguato per questo.


3
Non vedo niente di sbagliato nel primo. Se consideri il secondo un hack, la soluzione migliore è scrivere solo una funzione di utilità che esegue il controllo nullo.
Nick Larsen

per favore puoi essere più preciso sulla tua domanda
FosterZ

3
string.Format ("{0}", myObj) accetta valori nulli.
Holstebroe

3
Con C # 6.0 ora possiamo usare operatori condizionali null, come il testo? .ToString () o il testo? .Trim ()
Santosh

2
Per questa risposta Convert.ToString() fa esattamente la prima cosa che hai scritto sotto.
drzaus

Risposte:


175

Modifica C # 6.0:

Con C # 6.0 ora possiamo avere una versione succinta e priva di cast del metodo originale:

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

O anche usando l'interpolazione:

string s = $"{myObj}";

Risposta originale:

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

o

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

per essere ancora più concisi.

Sfortunatamente, come è stato sottolineato, spesso avrai bisogno di un cast su entrambi i lati per farlo funzionare con tipi non String o Object:

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

Pertanto, sebbene possa sembrare elegante, il cast è quasi sempre necessario e non è così succinto nella pratica.

Come suggerito altrove, consiglio forse di utilizzare un metodo di estensione per renderlo più pulito:

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

Questo verrà compilato? L'operatore di coalescenza non controlla i tipi?
Nick Larsen

1
Funziona poiché (object ?? string) restituisce object, perché coalesce utilizza il tipo meno comune. Ma penso che questo non funzionerà per le interfacce perché non può decidere quale interfaccia scegliere (poiché sono consentite più interfacce per classe).
codymanix

1
Non è proprio la soluzione che speravo, ma la accetterò
codymanix

4
Il downvoting del cast di quell'oggetto è terribilmente brutto e coinvolge la boxe.
steinar

1
la prima opzione per c # 6 è molto elegante
Alexandre N.

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

string.Format formatterà null come una stringa vuota e chiamerà ToString () su oggetti non null. A quanto ho capito, questo è quello che stavi cercando.


3
Personalmente non mi piace questo. Il codice potrebbe essere leggermente più corto di String s = myObj == null? "": myObj.ToString (), ma nascondi completamente il ragionamento alla base del tuo metodo.
AGuyCalledGerald

Certo, questa è la microottimizzazione, ma richiede circa 5 volte più a lungo del semplice "" + myObj. Ma ho letto che crea stringhe extra. str.Concat(myObj)sembra funzionare bene ed è "ancora più veloce".
drzaus

18

Sarebbe fantastico se Convert.ToString () avesse un sovraccarico adeguato per questo.

C'è stato un Convert.ToString(Object value).Net 2.0 (circa 5 anni prima che fosse chiesto questo Q), che sembra fare esattamente quello che vuoi:

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

Mi sto perdendo / interpretando male qualcosa di veramente ovvio qui?


1
Non lo fai, lo fanno. Perché semplice quando può essere complicato :)
alex.peter

13

Con un metodo di estensione, puoi ottenere ciò:

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

Quanto segue non scrive nulla sullo schermo e non genera un'eccezione:

        string value = null;

        Console.WriteLine(value.ToStringOrEmpty());

Le chiamate al metodo di estensione omettono il solito controllo per i valori nulli ...?
Matti Virkkunen

2
Aggiunge che non devi digitare "{0}" e che puoi scegliere un nome di metodo che descriva ciò che stai facendo. Ciò è particolarmente utile quando lo fai molte volte. Puoi anche denominare il metodo ToStringOrEmptyWhenNull.
Pieter van Ginkel

2
Se l'OP pensa che string s = "" + myObj;sia hacker, la chiamata di una funzione su un oggetto nullo dovrebbe rientrare nella stessa barca. Lo farei sottovalutare, ma risolve il problema a portata di mano, sono solo in disaccordo con l'uso. Gli oggetti nulli dovrebbero generare NullReferenceException, anche nei metodi di estensione.
Nick Larsen

2
@ NickLarsen: sono d'accordo con te nella maggior parte delle occasioni, ma a volte vuoi solo la comodità di una semplice chiamata al metodo. Il nome del metodo dovrebbe darti un suggerimento che i riferimenti nulli sono OK, come con la proposta di ToStringOrEmptyWhenNull.
Jordão

3
I metodi di estensione non generano quando il "primo" parametro (il thisparametro) perché sono solo zucchero sintattico. Questo è x.SomeExtensionMethod()è zucchero sintattico per SomeStaticClass.SomeExtensionMethod(x);Così, quando xè nullnon stiamo cercando di richiamare un metodo su un nulloggetto, ma piuttosto passando un nulloggetto a un metodo statico. Se e solo se quel metodo verifica la presenza di un nullparametro e genera quando lo incontra un metodo di estensione "invocato" su un nulloggetto verrà lanciato.
jason

7

Non sono d'accordo con questo:

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

è un hack in alcun modo. Penso che sia un buon esempio di codice chiaro. È assolutamente ovvio cosa vuoi ottenere e che ti aspetti nulla.

AGGIORNARE:

Vedo ora che non stavi dicendo che questo era un hack. Ma è implicito nella domanda che tu pensi che in questo modo non sia la strada da percorrere. Nella mia mente è sicuramente la soluzione più chiara.


Non ha detto che questo metodo fosse hack. In realtà non ha detto cosa c'era che non andava, tranne forse sottintendendo che non era semplice. Non credo ci sia niente di sbagliato in questo metodo. +1 perché lo farei in questo modo.
Mark Byers

Sono d'accordo con OP ... c'è già un operatore di coalescenza nullo in c # - vedi il mio post qui sotto.
Andrew Hanlon

Penso che l'operatore di coalescenza nullo sia un po 'meno chiaro in questo caso, tuttavia mi andrebbe bene usarlo.
steinar

@ Pieter abbastanza giusto. Ma lo fa. La domanda è "Esiste un modo semplice per eseguire quanto segue: ...". Quel modo esatto è semplice!
steinar

Non ho mai detto che questo metodo è un trucco. Per favore rileggi la mia domanda. Mi manca solo una piccola funzione nel Framework che ha questa funzionalità.
codymanix

4
string s = String.Concat(myObj);

sarebbe il modo più breve immagino e avrebbe anche un sovraccarico di prestazioni trascurabile. Tieni presente anche se non sarebbe abbastanza chiaro per il lettore del codice quale sia l'intenzione.


2
Questa è la forma esplicita di "" + myObj ma è anche peggio nel raccontare cosa sta succedendo qui. Interessante comunque.
codymanix

@codymanix non penso sia lo stesso - in Concatrealtà fa un controllo nullo sotto e ritorna string.Emptyo arg0.ToString(), che sembra essere leggermente più performante (voglio dire, stiamo parlando di ms qui).
drzaus

2

in realtà non ho capito cosa vuoi fare. A quanto ho capito, puoi scrivere questo codice in un altro modo come questo. Lo stai chiedendo o no? Puoi spiegare di più?

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

Certo di poterlo scrivere in questo modo, ma voglio una semplice piccola chiamata di funzione, mi chiedevo perché non c'è niente di simile in .NET BCL
codymanix

Hai davvero bisogno di una funzione mentre abbiamo il metodo IsNullOrEmpty ()?
Serkan Hekimoglu

In questa nota, ho sempre desiderato che l'operatore di coalescenza fallisse successivamente una volta che raggiunge un riferimento nullo nella tua espressione fluente, ma capisco perfettamente perché questa è un'idea terribile. Sarebbe bello anche un override che ti permetta di farlo.
Nick Larsen

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

2

Potrei essere picchiato per la mia risposta, ma qui va comunque:

Vorrei semplicemente scrivere

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

C'è un payoff in termini di prestazioni per l'utilizzo dell'operatore ternario? Non lo so dalla parte superiore della mia testa.

E chiaramente, come qualcuno sopra menzionato, puoi inserire questo comportamento in un metodo come safeString (myObj) che ne consente il riutilizzo.


OMG se l'oggetto è nullo quindi chiamare ToString () su di esso?
codymanix

Andiamo, è un errore di battitura. Ho sostituito il primo = con! per correggerlo. Ma davvero mi fai -1 per un errore di battitura?
jaydel

2

Ho avuto lo stesso problema e l'ho risolto semplicemente lanciando l'oggetto su una stringa. Questo funziona anche per gli oggetti nulli perché le stringhe possono essere nulle. A meno che tu non voglia assolutamente avere una stringa nulla, dovrebbe funzionare bene:

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

La soluzione più breve e migliore. (Obj1 ?? "") .ToString () in realtà prima lancia Obj1 anche come stringa :)
TPAKTOPA

2

Alcuni test delle prestazioni (velocità) che riassumono le varie opzioni, non che importi davvero #microoptimization (utilizzando un'estensione linqpad )

Opzioni

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();
}

Probabilmente è importante sottolineare che Convert.ToString(...)manterrà una stringa nulla.

Risultati

Oggetto

  • nullcheck 1,00x 1221 tick trascorsi (0,1221 ms) [in 10.000 ripetizioni, 1.221E-05 ms per]
  • coallesce 1,14 x 1387 tick trascorsi (0,1387 ms) [in 10K ripetizioni, 1,387E-05 ms per]
  • stringa + 1,16 x 1415 tick trascorsi (0,1415 ms) [in 10K ripetizioni, 1,415E-05 ms per]
  • str.Concat 1,16 x 1420 tick trascorsi (0,142 ms) [in 10.000 ripetizioni, 1,42E-05 ms per]
  • Converti 1,58 x 1931 tick trascorsi (0,1931 ms) [in 10.000 ripetizioni, 1,931E-05 ms per]
  • str.Format 5,45 x 6655 tick trascorsi (0,6655 ms) [in 10.000 ripetizioni, 6,655E-05 ms per]

Corda

  • nullcheck 1,00 x 1190 tick trascorsi (0,119 ms) [in 10.000 ripetizioni, 1,19E-05 ms per]
  • Converti 1,01 x 1200 tick trascorsi (0,12 ms) [in 10.000 ripetizioni, 1,2E-05 ms per]
  • stringa + 1,04 x 1239 tick trascorsi (0,1239 ms) [in 10K ripetizioni, 1,239E-05 ms per]
  • coallesce 1,20 x 1423 tick trascorsi (0,1423 ms) [in 10.000 ripetizioni, 1,423E-05 ms per]
  • str.Concat 4,57x 5444 tick trascorsi (0,5444 ms) [in 10.000 ripetizioni, 5,444E-05 ms per]
  • str.Format 5,67 x 6750 tick trascorsi (0,675 ms) [in 10.000 ripetizioni, 6,75E-05 ms per]

1

Il commento di Holstebroe sarebbe la tua migliore risposta:

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

Se myObjè null, Format inserisce un valore di stringa vuota.

Soddisfa anche il requisito di una riga ed è di facile lettura.


si, ma il codice non è chiaro. Quanti dei tuoi colleghi sviluppatori sapranno cosa stai cercando di ottenere?
AGuyCalledGerald

0

Anche se questa è una vecchia domanda e l'OP ha chiesto C #, vorrei condividere una soluzione VB.Net per coloro che lavorano con VB.Net piuttosto che C #:

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

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

Sfortunatamente VB.Net non consente l'operatore? -Dopo una variabile, quindi myObj? .ToString non è valido (almeno non in .Net 4.5, che ho usato per testare la soluzione). Invece utilizzo If per restituire una stringa vuota nel caso in cui myObj sia Nothing. Quindi il primo Tostring-Call restituisce una stringa vuota, mentre il secondo (dove myObj non è Nothing) restituisce "42".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.