Bagaimana cara melakukan ToString untuk objek yang kemungkinan nol?

99

Adakah cara sederhana untuk melakukan hal berikut:

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

Saya tahu saya dapat melakukan hal berikut, tetapi saya benar-benar menganggapnya sebagai peretasan:

String s = "" + myObj;

Akan lebih bagus jika Convert.ToString () memiliki kelebihan beban yang tepat untuk ini.

codymanix.dll
sumber
3
Saya tidak melihat ada yang salah dengan yang pertama. Jika Anda menganggap yang kedua sebagai peretasan, taruhan terbaik Anda adalah menulis fungsi utilitas yang melakukan pemeriksaan nol.
Nick Larsen
tolong, bisakah Anda lebih tepat tentang pertanyaan Anda
FosterZ
3
string.Format ("{0}", myObj) menerima nilai null.
Holstebroe
3
Dengan C # 6.0 kita sekarang dapat menggunakan operator bersyarat nol, seperti theText? .ToString () atau theText? .Trim ()
Santosh
2
Per jawaban Convert.ToString() ini persis seperti hal pertama yang Anda tulis di bawahnya.
drzaus

Jawaban:

179

C # 6.0 Edit:

Dengan C # 6.0 kita sekarang dapat memiliki versi singkat dan bebas cast dari metode orignal:

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

Atau bahkan menggunakan interpolasi:

string s = $"{myObj}";

Jawaban Asli:

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

atau

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

menjadi lebih ringkas.

Sayangnya, seperti yang telah ditunjukkan, Anda akan sering membutuhkan cast di kedua sisi untuk membuat ini berfungsi dengan tipe non String atau Object:

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

Oleh karena itu, meski mungkin tampak elegan, pemerannya hampir selalu diperlukan dan tidak sesingkat itu dalam praktiknya.

Seperti yang disarankan di tempat lain, saya merekomendasikan mungkin menggunakan metode ekstensi untuk membuat ini lebih bersih:

public static string ToStringNullSafe(this object value)
{
    return (value ?? string.Empty).ToString();
}
Andrew Hanlon
sumber
Akankah ini mengkompilasi? Bukankah tipe cek operator penggabungan?
Nick Larsen
1
Ia bekerja karena (object ?? string) mengembalikan objek, karena penggabungan menggunakan tipe paling umum. Tetapi saya pikir ini tidak akan berfungsi untuk antarmuka karena tidak dapat memutuskan antarmuka mana yang harus dipilih (karena beberapa antarmuka diizinkan per kelas).
codymanix
1
Bukan solusi yang saya harapkan tetapi saya akan menerimanya
codymanix
4
Downvoting sebagai objek yang dilemparkan sangat jelek dan melibatkan tinju.
steinar
1
pilihan pertama untuk c # 6 sangat elegan
Alexandre N.
40
string.Format("{0}", myObj);

string.Format akan memformat null sebagai string kosong dan memanggil ToString () pada objek bukan null. Seperti yang saya pahami, inilah yang Anda cari.

Holstebroe
sumber
3
Saya pribadi tidak suka ini. Kode tersebut mungkin lebih pendek secara signifikan dari String s = myObj == null? "": myObj.ToString (), tetapi Anda benar-benar menyembunyikan alasan di balik metode Anda.
AGuyCalledGerald
Memang ini adalah pengoptimalan mikro, tetapi ini membutuhkan waktu sekitar 5x lebih lama "" + myObj. Tapi saya pernah membaca bahwa menciptakan string ekstra. str.Concat(myObj)tampaknya bekerja dengan baik dan "bahkan lebih cepat".
drzaus
18

Akan lebih bagus jika Convert.ToString () memiliki kelebihan beban yang tepat untuk ini.

Sudah ada Convert.ToString(Object value).Net 2.0 (kira-kira 5 tahun sebelum Q ini diminta), yang tampaknya melakukan apa yang Anda inginkan:

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

Apakah saya melewatkan / salah menafsirkan sesuatu yang sangat jelas di sini?

Rob Gilliam
sumber
1
Anda tidak, mereka melakukannya. Mengapa sederhana ketika itu bisa menjadi rumit :)
alex.peter
13

Dengan metode ekstensi, Anda dapat melakukannya:

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

Hal berikut tidak akan menulis apa pun ke layar dan tidak akan membuat pengecualian:

        string value = null;

        Console.WriteLine(value.ToStringOrEmpty());
Pieter van Ginkel
sumber
Apakah panggilan metode ekstensi menghilangkan pemeriksaan biasa untuk nulls ...?
Matti Virkkunen
2
Ini menambahkan bahwa Anda tidak perlu mengetik "{0}" dan Anda dapat memilih nama metode yang mendeskripsikan apa yang Anda lakukan. Ini sangat berguna ketika Anda melakukan ini berkali-kali. Anda bahkan dapat memberi nama metode ToStringOrEmptyWhenNull.
Pieter van Ginkel
2
Jika OP menganggap itu string s = "" + myObj;hackish, memanggil fungsi pada objek null harus termasuk dalam perahu yang sama. Saya akan merendahkan ini, tetapi itu menyelesaikan masalah yang ada, saya hanya tidak setuju dengan penggunaannya. Objek nol harus dilempar NullReferenceException, bahkan dalam metode ekstensi.
Nick Larsen
2
@NickLarsen: Saya setuju dengan Anda di sebagian besar kesempatan, tetapi terkadang Anda hanya ingin kenyamanan panggilan metode sederhana. Nama metode akan memberi Anda petunjuk bahwa referensi null OK, seperti dengan proposal untuk ToStringOrEmptyWhenNull.
Jordão
3
Metode ekstensi tidak membuang saat parameter "pertama" ( thisparameter) karena mereka hanya gula sintaksis. Itulah x.SomeExtensionMethod()adalah sintaksis gula untuk SomeStaticClass.SomeExtensionMethod(x);Jadi, ketika xyang nullkita tidak mencoba untuk memanggil metode pada nullobjek melainkan melewati nullobjek untuk metode statis. Jika dan hanya jika metode tersebut memeriksa nullparameter dan melempar saat menjumpainya akan metode ekstensi "dipanggil" pada nulllemparan objek.
jason
7

Saya tidak setuju dengan ini:

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

adalah peretasan dengan cara apa pun. Saya pikir ini adalah contoh yang bagus dari kode yang jelas. Sangat jelas apa yang ingin Anda capai dan bahwa Anda mengharapkan nol.

MEMPERBARUI:

Saya mengerti sekarang bahwa Anda tidak mengatakan bahwa ini adalah retasan. Tetapi tersirat dalam pertanyaan bahwa menurut Anda cara ini bukanlah cara yang tepat. Menurut saya, ini adalah solusi yang paling jelas.

steinar
sumber
Dia tidak mengatakan bahwa metode ini diretas. Sebenarnya dia tidak mengatakan apa yang salah dengan itu kecuali mungkin menyiratkan bahwa itu tidak sederhana. Saya tidak berpikir ada yang salah dengan metode ini. +1 karena saya akan melakukannya dengan cara ini.
Mark Byers
Saya setuju dengan OP ... sudah ada operator penggabungan nol di c # - lihat posting saya di bawah.
Andrew Hanlon
Saya pikir operator penggabungan nol sedikit kurang jelas dalam kasus ini, namun saya akan baik-baik saja dengan menggunakannya.
Steinar
@ Peter Cukup adil. Tapi memang begitu. Pertanyaannya adalah "Apakah ada cara sederhana untuk melakukan hal berikut: ...". Cara yang tepat itu sederhana!
Steinar
Saya tidak pernah mengatakan, bahwa metode ini adalah retasan. Harap baca ulang pertanyaan saya. Saya hanya melewatkan sedikit fungsi dalam Kerangka yang memiliki fungsi ini.
codymanix
4
string s = String.Concat(myObj);

akan menjadi cara terpendek yang saya kira dan juga memiliki overhead kinerja yang dapat diabaikan. Perlu diingat meskipun tidak cukup jelas bagi pembaca kode apa maksudnya.

herzmeister
sumber
2
Ini adalah bentuk eksplisit dari "" + myObj tetapi lebih buruk lagi dalam menceritakan apa yang terjadi di sini. Menarik juga.
codymanix
@codymanix saya tidak berpikir itu sama - Concatsebenarnya melakukan pemeriksaan nol di bawah dan mengembalikan string.Emptyatau arg0.ToString(), yang tampaknya sedikit lebih berkinerja (maksud saya, kita berbicara tentang ms di sini).
drzaus
2

sebenarnya saya tidak mengerti apa yang ingin Anda lakukan. Seperti yang saya pahami, Anda dapat menulis kode ini dengan cara lain seperti ini. Apakah Anda menanyakan ini atau tidak? Bisakah Anda menjelaskan lebih lanjut?

string s = string.Empty;
    if(!string.IsNullOrEmpty(myObj))
    {
    s = myObj.ToString();
    }
Serkan Hekimoglu
sumber
Tentu saya bisa menulisnya seperti ini tetapi saya ingin panggilan fungsi kecil yang sederhana, saya bertanya-tanya mengapa tidak ada yang seperti ini di .NET BCL
codymanix
Apakah Anda benar-benar memerlukan fungsi saat kami memiliki metode IsNullOrEmpty ()?
Serkan Hekimoglu
Pada catatan itu, saya selalu ingin operator penggabungan gagal berikutnya setelah mencapai referensi nol dalam ekspresi fasih Anda, tetapi saya benar-benar mengerti mengapa itu adalah ide yang buruk. Penimpaan yang memungkinkan Anda melakukan itu akan menyenangkan juga.
Nick Larsen
1
string s = string.IsNullOrEmpty(myObj) ? string.Empty : myObj.ToString();
Nick Larsen
2

Saya mungkin akan dihajar untuk jawaban saya tetapi ini dia:

Saya hanya akan menulis

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

Apakah ada hasil dalam hal kinerja untuk menggunakan operator terner? Saya tidak tahu di luar kepala saya.

Dan jelas, seperti yang disebutkan seseorang di atas, Anda dapat menempatkan perilaku ini ke dalam metode seperti safeString (myObj) yang memungkinkan untuk digunakan kembali.

jaydel
sumber
OMG jika objek null lalu panggil ToString () di atasnya?
codymanix
Ayo, itu salah ketik. Saya telah mengganti yang pertama = dengan! untuk memperbaikinya. Tapi Anda benar-benar akan -1 saya karena salah ketik?
jaydel
2

Saya memiliki masalah yang sama dan menyelesaikannya hanya dengan mentransmisikan objek ke string. Ini juga berfungsi untuk objek null karena string bisa berupa null. Kecuali Anda benar-benar tidak ingin memiliki string null, ini seharusnya berfungsi dengan baik:

string myStr = (string)myObj; // string in a object disguise or a null
jahu
sumber
Solusi terpendek dan terbaik. (Obj1 ?? "") .ToString () sebenarnya pertama kali menggunakan Obj1 sebagai string juga :)
TPAKTOPA
2

Beberapa tes kinerja (kecepatan) meringkas berbagai opsi, bukan berarti #microoptimization benar-benar penting (menggunakan ekstensi linqpad )

Pilihan

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

Mungkin penting untuk menunjukkan bahwa Convert.ToString(...)akan mempertahankan string nol.

Hasil

Obyek

  • nullcheck 1,00x 1221 ticks berlalu (0,1221 ms) [dalam 10 ribu repetisi, 1,221E-05 ms per]
  • coallesce 1,14x 1387 ticks berlalu (0,1387 md) [dalam 10K repetisi, 1,387E-05 ms per]
  • string + 1,16x 1415 ticks berlalu (0,1415 ms) [dalam 10K repetisi, 1,415E-05 ms per]
  • str.Concat 1,16x 1420 ticks telah berlalu (0,142 ms) [dalam 10K repetisi, 1,42E-05 ms per]
  • Konversi 1,58x 1931 ticks berlalu (0,1931 ms) [dalam 10K repetisi, 1,931E-05 ms per]
  • str.Format 5,45x 6655 ticks berlalu (0,6655 ms) [dalam 10K repetisi, 6,655E-05 ms per]

Tali

  • nullcheck 1,00x 1190 ticks berlalu (0,199 md) [dalam 10K repetisi, 1,19E-05 ms per]
  • Ubah 1,01x 1200 ticks berlalu (0,12 ms) [dalam 10K repetisi, 1,2E-05 ms per]
  • string + 1,04x 1239 ticks berlalu (0,1239 md) [dalam 10K repetisi, 1,239E-05 ms per]
  • coallesce 1,20x 1423 ticks berlalu (0,1423 ms) [dalam 10K repetisi, 1,423E-05 ms per]
  • str.Concat 4,57x 5444 ticks berlalu (0,5444 ms) [dalam 10K repetisi, 5,444E-05 ms per]
  • str.Format 5,67x 6750 ticks berlalu (0,675 ms) [dalam 10K repetisi, 6,75E-05 ms per]
drzaus
sumber
1

Komentar Holstebroe akan menjadi jawaban terbaik Anda:

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

Jika myObj null, Format menempatkan nilai String Kosong di sana.

Ini juga memenuhi persyaratan satu baris Anda dan mudah dibaca.

jp2code
sumber
ya, tapi kodenya tidak jelas. Berapa banyak rekan pengembang Anda yang tahu apa yang ingin Anda capai?
AGuyCalledGerald
0

Meskipun ini adalah pertanyaan lama dan OP meminta C #, saya ingin membagikan solusi VB.Net untuk mereka yang bekerja dengan VB.Net daripada C #:

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

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

Sayangnya VB.Net tidak mengizinkan? -Operator setelah variabel jadi myObj? .ToString tidak valid (setidaknya tidak dalam .Net 4.5, yang saya gunakan untuk menguji solusi). Sebagai gantinya saya menggunakan If untuk mengembalikan string kosong jika myObj ist Nothing. Jadi Tostring-Call pertama mengembalikan string kosong, sedangkan yang kedua (di mana myObj bukan Nothing) mengembalikan "42".

Sascha
sumber