Olası bir boş nesne için ToString nasıl yapılır?


104

Aşağıdakileri yapmanın basit bir yolu var mı:

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

Aşağıdakileri yapabileceğimi biliyorum ama bunu gerçekten bir hack olarak görüyorum:

String s = "" + myObj;

Convert.ToString () bunun için uygun bir aşırı yüklemeye sahip olsaydı harika olurdu.


3
İlkinde yanlış bir şey görmüyorum. İkincinin bir hack olduğunu düşünürseniz, en iyisi boş kontrolü yapan bir yardımcı program işlevi yazmaktır.
Nick Larsen

lütfen sorunuz hakkında daha kesin bilgi verebilir misiniz
FosterZ

3
string.Format ("{0}", myObj) boş değerleri kabul eder.
Holstebroe

3
? C # ile 6.0 şimdi () thetext .ToString () veya thetext .Trim gibi boş-koşullu operatörleri, kullanabilirsiniz
Santosh

2
Başına bu cevap Convert.ToString() Altında yazdığı tam olarak ilk şeyi yapar.
drzaus

Yanıtlar:


184

C # 6.0 Düzenleme:

C # 6.0 ile artık orijinal yöntemin kısa ve öz bir sürümüne sahip olabiliriz:

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

Veya enterpolasyon kullanarak bile:

string s = $"{myObj}";

Orijinal Cevap:

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

veya

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

daha da özlü olmak.

Ne yazık ki, belirtildiği gibi, bunun String veya Object olmayan türlerle çalışmasını sağlamak için genellikle her iki tarafta bir cast'e ihtiyacınız olacak:

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

Bu nedenle, zarif görünse de, oyuncu kadrosu neredeyse her zaman gereklidir ve pratikte o kadar da özlü değildir.

Başka bir yerde önerildiği gibi, bunu daha temiz hale getirmek için bir uzatma yöntemi kullanmanızı tavsiye ederim:

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

Bu derlenecek mi? Birleştirme operatörü türleri kontrol etmiyor mu?
Nick Larsen

1
Birleştirme en az yaygın türü kullandığı için (nesne ?? dizge) nesne döndürdüğü için çalışır. Ancak bunun arayüzler için işe yaramayacağını düşünüyorum çünkü hangi arayüzün seçileceğine karar veremiyor (çünkü sınıf başına birden fazla arayüze izin verilmektedir).
codymanix

1
Gerçekten umduğum çözüm değil ama kabul
edeceğim

4
Bu nesnenin yayınlanması son derece çirkin ve boks yapmayı gerektirdiği için olumsuz oy kullanmak.
steinar

1
c # 6 için ilk seçenek çok zarif
Alexandre N.

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

string.Format, null'u boş bir dize olarak biçimlendirecek ve boş olmayan nesnelerde ToString () 'i çağıracaktır. Anladığım kadarıyla, aradığınız şey bu.


3
Şahsen bundan hoşlanmadım. Kod, String s = myObj == null? Değerinden önemli ölçüde daha kısa olabilir. "": myObj.ToString (), ancak yönteminizin arkasındaki mantığı tamamen gizliyorsunuz.
AGuyCalledGerald

Bunun mikrooptimizasyon olduğu kabul edilir, ancak sadece 5 kat daha uzun sürer "" + myObj. Ama bunun fazladan dizeler yarattığını okudum. str.Concat(myObj)gayet iyi çalışıyor gibi görünüyor ve "daha da hızlı".
drzaus

19

Convert.ToString () bunun için uygun bir aşırı yüklemeye sahip olsaydı harika olurdu.

Meydana gelmiş bir Convert.ToString(Object value).NET 2.0 beri (yaklaşık 5 yıl önce istendi bu Q.) Ne istediğinizi tam olarak yapmak görünür:

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

Burada gerçekten açık olan bir şeyi kaçırıyor muyum / yanlış yorumluyorum?


2
Yapmazsın, yaparlar. Karmaşık olabildiği zaman neden basit :)
alex.peter

13

Bir uzatma yöntemi ile bunu başarabilirsiniz:

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

Aşağıdakiler ekrana hiçbir şey yazmaz ve bir istisna atmaz:

        string value = null;

        Console.WriteLine(value.ToStringOrEmpty());

Uzantı yöntemi çağrıları, her zamanki boş değer kontrolünü atlıyor mu?
Matti Virkkunen

2
"{0}" yazmanız gerekmediğini ve ne yaptığınızı açıklayan bir yöntem adı seçebileceğinizi ekler. Bu, özellikle bunu birçok kez yaptığınızda yararlıdır. ToStringOrEmptyWhenNull yöntemini bile adlandırabilirsiniz.
Pieter van Ginkel

2
OP bunun string s = "" + myObj;hack olduğunu düşünürse, boş bir nesnede bir işlevi çağırmak aynı tekneye düşmelidir. Buna olumsuz oy verirdim, ancak eldeki sorunu çözüyor, sadece kullanıma katılmıyorum. Null nesneler NullReferenceException, uzantı yöntemlerinde bile atmalıdır.
Nick Larsen

2
@NickLarsen: Çoğu durumda size katılıyorum, ancak bazen basit bir yöntem çağrısının rahatlığını istiyorsunuz. Yöntem adı, önerisinde olduğu gibi boş referansların uygun olduğuna dair bir ipucu vermelidir ToStringOrEmptyWhenNull.
Jordão

3
Uzatma yöntemleri thissadece sözdizimsel şeker oldukları için "ilk" parametre ( parametre) olduğunda atmazlar. Yani x.SomeExtensionMethod()için sözdizimsel şeker SomeStaticClass.SomeExtensionMethod(x);Böylece zaman xolduğu nullbiz bir yöntemi çağırmak çalışırken değildir nullnesne ziyade geçen bir nullstatik yönteme nesneyi. Yalnızca ve ancak bu yöntem bir nullparametreyi kontrol ederse ve böyle bir durumla karşılaştığında atarsa, bir nullnesne atışında bir uzantı yöntemi "çağrılır" .
jason

7

Buna katılmıyorum:

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

herhangi bir şekilde bir hack'tir. Bence bu açık kod için iyi bir örnek. Neye ulaşmak istediğiniz ve boş beklediğiniz kesinlikle açıktır.

GÜNCELLEME:

Şimdi bunun bir hile olduğunu söylemediğini anlıyorum. Ancak soruda, bu yolun gidecek yol olmadığını düşündüğünüz ima ediliyor. Bence kesinlikle en net çözüm bu.


Bu yöntemin hack olduğunu söylemedi. Aslında, belki de basit olmadığını ima etmek dışında neyin yanlış olduğunu söylemedi. Bu yöntemde yanlış bir şey olduğunu düşünmüyorum. +1 çünkü bu şekilde yapardım.
Mark Byers

OP'ye katılıyorum ... c # içinde zaten boş bir birleştirme operatörü var - aşağıdaki yazıma bakın.
Andrew Hanlon

Boş birleştirme operatörünün bu durumda biraz daha az net olduğunu düşünüyorum, ancak bunu kullanmakta da sorun olmaz.
steinar

@Pieter Fair Yeterince. Ama öyle. Soru şu: "Aşağıdakileri yapmanın basit bir yolu var mı: ...". Tam olarak bu yol basit!
steinar

Bu yöntemin bir hack olduğunu hiç söylemedim . Lütfen sorumu tekrar okuyun. Framework'te bu işleve sahip küçük bir işlevi özledim.
codymanix

4
string s = String.Concat(myObj);

tahmin ettiğim en kısa yol olurdu ve ayrıca ihmal edilebilir performans yükü de olur. Kod okuyucusu için niyetin ne olduğu pek açık olmasa da aklınızda bulundurun.


2
Bu, "" + myObj'nin açık biçimidir, ancak burada neler olup bittiğini anlatmak daha da kötüdür. Yine de ilginç.
codymanix

@codymanix bunun aynı olduğunu düşünmüyorum - Concataslında altında boş bir kontrol yapıyor ve geri dönüyor string.Emptyya arg0.ToString()da biraz daha performanslı görünüyor (yani, burada ms'den bahsediyoruz).
drzaus

2

aslında ne yapmak istediğini anlamadım. Anladığım kadarıyla, bu kodu bunun gibi başka bir şekilde yazabilirsiniz. Bunu soruyor musun, istemiyor musun? Biraz daha fazla açıklayabilir misin?

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

Elbette bunu böyle yazabilirim ama basit bir küçük işlev çağrısı istiyorum, .NET
BCL'de

IsNullOrEmpty () yöntemine sahipken gerçekten bir işleve ihtiyacınız var mı?
Serkan Hekimoğlu

Bu notta, akıcı ifadenizde boş bir referansa ulaştığında birleştirme operatörünün başarısız olmasını hep istemişimdir, ancak bunun neden korkunç bir fikir olduğunu tamamen anlıyorum. Bunu yapmanıza izin veren bir geçersiz kılma da güzel olurdu.
Nick Larsen

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

2

Cevabım için dayak yiyebilirim ama işte yine de:

Basitçe yazarım

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

Üçlü operatörü kullanmanın performans açısından bir getirisi var mı? Aklımın ucunu bilmiyorum.

Ve açıkça, yukarıda bahsettiğimiz gibi, bu davranışı yeniden kullanıma izin veren safeString (myObj) gibi bir yönteme koyabilirsiniz.


OMG, nesne null ise o zaman ToString () çağrılsın mı?
codymanix

Hadi, bu bir yazım hatası. İlk = ile değiştirdim! doğru yapmak için. Ama bir yazım hatası için gerçekten -1 mi olacaksın?
jaydel

2

Ben de aynı sorunu yaşadım ve basitçe nesneyi dizeye çevirerek çözdüm. Bu, boş nesneler için de işe yarar çünkü dizeler boş olabilir. Bir boş dizeye sahip olmak istemediğiniz sürece, bu gayet iyi çalışmalıdır:

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

En kısa ve en iyi çözüm. (Obj1 ?? "") .ToString () aslında ilk olarak
Obj1'i

2

Çeşitli seçenekleri özetleyen bazı (hız) performans testleri, bunun gerçekten önemli olduğunu değil #microoptimization ( linqpad uzantısı kullanarak )

Seçenekler

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

Convert.ToString(...)Boş bir dizge tutacağına işaret etmek muhtemelen önemlidir .

Sonuçlar

Nesne

  • nullcheck 1.00x 1221 tik geçti (0.1221 ms) [10K tekrar olarak, 1.221E-05 ms başına]
  • coallesce 1,14x 1387 işaretleme süresi (0,1387 ms) [10K tekrar olarak, 1,387E-05 ms başına]
  • dizi + 1,16x 1415 işaretleme süresi (0,1415 ms) [10K tekrar olarak, 1,415E-05 ms başına]
  • str.Concat 1,16x 1420 tik sayısı geçti (0,142 ms) [10K tekrar, 1,42E-05 ms başına]
  • Geçen 1,58x 1931 işaretini dönüştürme (0,1931 ms) [10K tekrar olarak, 1,931E-05 ms başına]
  • str.Format 5.45x 6655 tıklanma sayısı (0.6655 ms) [10K tekrar olarak, 6.655E-05 ms başına]

Dize

  • nullcheck 1.00x 1190 tıklama geçti (0.119 ms) [10K tekrar olarak, 1.19E-05 ms başına]
  • Geçen 1,01x 1200 işaretlemeyi dönüştürme (0,12 ms) [10K tekrar, 1,2E-05 ms başına]
  • dize + 1,04x 1239 işaretleme süresi (0,1239 ms) [10K tekrar olarak, 1,239E-05 ms başına]
  • coallesce 1,20x 1423 tik geçti (0,1423 ms) [10K tekrar olarak, 1,423E-05 ms başına]
  • str.Concat 4,57x 5444 tik geçti (0,5444 ms) [10K tekrar, 5,444E-05 ms başına]
  • str.Format 5,67x 6750 tıklama sayısı (0,675 ms) [10K tekrar, 6,75E-05 ms başına]

1

Holstebroe'nin yorumu en iyi cevabınız olacaktır:

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

Eğer myObjnull, Biçim orada bir boş dize değeri yerleştirir.

Ayrıca tek satırlık gereksinimlerinizi karşılar ve okunması kolaydır.


evet, ancak kod net değil. Ne başarmaya çalıştığınızı geliştirici arkadaşlarınızdan kaç tanesi bilecek?
AGuyCalledGerald

0

Bu eski bir soru olmasına ve OP'nin C # istemesine rağmen C # yerine VB.Net ile çalışanlar için bir VB.Net çözümünü paylaşmak istiyorum:

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

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

Ne yazık ki VB.Net bir değişkenden sonra? -Operatörüne izin vermiyor, bu yüzden myObj? .ToString geçerli değil (en azından çözümü test etmek için kullandığım .Net 4.5'te değil). Bunun yerine, myObj ist Nothing durumunda boş bir dizge döndürmek için If kullanıyorum. Bu nedenle, ilk Tostring-Call boş bir dizge döndürür, ikincisi (myObj hiçbir şey değildir) "42" döndürür.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.