วิธีการทำ ToString สำหรับวัตถุว่าง


104

มีวิธีง่ายๆในการดำเนินการดังต่อไปนี้:

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

ฉันรู้ว่าฉันสามารถทำสิ่งต่อไปนี้ได้ แต่ฉันคิดว่ามันเป็นการแฮ็กจริงๆ:

String s = "" + myObj;

มันจะดีมากถ้า Convert ToString () มีโอเวอร์โหลดที่เหมาะสมสำหรับสิ่งนี้


3
ไม่เห็นมีอะไรผิดปกติกับอันแรก หากคุณคิดว่าอย่างที่สองเป็นการแฮ็กคุณทางที่ดีที่สุดคือเขียนฟังก์ชันยูทิลิตี้ซึ่งทำการตรวจสอบค่าว่าง
Nick Larsen

โปรดระบุคำถามของคุณให้แม่นยำยิ่งขึ้น
FosterZ

3
string.Format ("{0}", myObj) ยอมรับค่า null
Holstebroe

3
ด้วย C # 6.0 ตอนนี้เราสามารถใช้ตัวดำเนินการที่มีเงื่อนไขว่างเช่น theText? .oString () หรือ theText? .Trim ()
Santosh

2
ตามคำตอบ Convert.ToString()นี้เป็นสิ่งแรกที่คุณเขียนไว้ข้างใต้
drzaus

คำตอบ:


184

C # 6.0 แก้ไข:

ด้วย C # 6.0 ตอนนี้เราสามารถมีวิธีการ orignal เวอร์ชันที่กระชับและไม่ต้องร่าย:

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

หรือแม้กระทั่งการใช้การแก้ไข:

string s = $"{myObj}";

คำตอบเดิม:

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

หรือ

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

ให้รัดกุมยิ่งขึ้น

น่าเสียดายที่ตามที่ได้ระบุไว้คุณมักจะต้องใช้นักแสดงที่ด้านใดด้านหนึ่งเพื่อให้สามารถใช้งานได้กับประเภทที่ไม่ใช่ String หรือ Object:

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

ดังนั้นในขณะที่มันอาจจะดูหรูหรา แต่นักแสดงมักจะมีความจำเป็นและไม่ได้รวบรัดในทางปฏิบัติ

ตามที่แนะนำไว้ที่อื่นฉันขอแนะนำให้ใช้วิธีการขยายเพื่อทำความสะอาด:

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

จะคอมไพล์ไหม ตัวดำเนินการรวมกันไม่ตรวจสอบประเภทหรือไม่?
Nick Larsen

1
ใช้งานได้ตั้งแต่ (object ?? string) ส่งคืนอ็อบเจ็กต์เนื่องจาก coalesce ใช้ชนิดทั่วไปน้อยที่สุด แต่ฉันคิดว่าสิ่งนี้จะใช้ไม่ได้กับอินเทอร์เฟซเนื่องจากไม่สามารถตัดสินใจได้ว่าจะเลือกอินเทอร์เฟซใด (เนื่องจากอนุญาตให้มีหลายอินเทอร์เฟซต่อคลาส)
codymanix

1
ไม่ใช่วิธีแก้ปัญหาที่ฉันคาดหวัง แต่ฉันจะยอมรับ
codymanix

4
การลงคะแนนเนื่องจากวัตถุนั้นน่าเกลียดมากและเกี่ยวข้องกับการชกมวย
steinar

1
ตัวเลือกแรกของ c # 6 นั้นสวยงามมาก
Alexandre N.

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

string.Format จะจัดรูปแบบ null เป็นสตริงว่างและเรียก ToString () บนอ็อบเจ็กต์ที่ไม่ใช่ null ตามที่ฉันเข้าใจนี่คือสิ่งที่คุณกำลังมองหา


3
ส่วนตัวไม่ชอบแบบนี้ รหัสอาจสั้นกว่า String s = myObj == null? "": myObj ToString () แต่คุณปกปิดเหตุผลเบื้องหลังวิธีการของคุณโดยสิ้นเชิง
AGuyCalledGerald

ที่ได้รับนี้เป็น microoptimization แต่มันจะใช้เวลาประมาณ 5 "" + myObjเท่านานกว่าเพียง แต่ฉันอ่านแล้วว่าสร้างสตริงพิเศษ str.Concat(myObj)ดูเหมือนจะทำงานได้ดีและ "เร็วยิ่งขึ้น"
drzaus

19

มันจะดีมากถ้า Convert ToString () มีโอเวอร์โหลดที่เหมาะสมสำหรับสิ่งนี้

มีมาConvert.ToString(Object value)ตั้งแต่. Net 2.0 (ประมาณ 5 ปีก่อนถามคำถามนี้) ซึ่งดูเหมือนจะทำในสิ่งที่คุณต้องการ:

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

ฉันพลาด / ตีความบางสิ่งที่ชัดเจนที่นี่ผิดหรือเปล่า


2
คุณไม่ทำ ทำไมง่ายเมื่อมันซับซ้อน :)
alex.peter

13

ด้วยวิธีการขยายคุณสามารถทำได้:

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

สิ่งต่อไปนี้จะไม่เขียนอะไรบนหน้าจอและจะไม่เกิดข้อยกเว้น:

        string value = null;

        Console.WriteLine(value.ToStringOrEmpty());

การเรียกเมธอดส่วนขยายละเว้นการตรวจสอบค่าว่างตามปกติ ... หรือไม่
Matti Virkkunen

2
เพิ่มว่าคุณไม่จำเป็นต้องพิมพ์ "{0}" และคุณสามารถเลือกชื่อวิธีการที่อธิบายถึงสิ่งที่คุณกำลังทำอยู่ สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อคุณทำสิ่งนี้หลาย ๆ ครั้ง คุณสามารถตั้งชื่อเมธอด ToStringOrEmptyWhenNull ได้
Pieter van Ginkel

2
หาก OP คิดว่าstring s = "" + myObj;เป็นการแฮ็กการเรียกใช้ฟังก์ชันบนวัตถุว่างก็ควรตกอยู่ในเรือลำเดียวกัน ฉันจะลงคะแนนสิ่งนี้ แต่มันช่วยแก้ปัญหาได้ฉันแค่ไม่เห็นด้วยกับการใช้งาน วัตถุที่เป็นโมฆะควรโยนNullReferenceExceptionแม้ในวิธีการขยาย
Nick Larsen

2
@NickLarsen: ฉันเห็นด้วยกับคุณเกือบทุกครั้ง แต่บางครั้งคุณก็ต้องการความสะดวกในการโทรแบบง่ายๆ ชื่อวิธีการควรให้คำแนะนำที่อ้างอิง null จะ OK, ToStringOrEmptyWhenNullเช่นเดียวกับข้อเสนอสำหรับ
Jordão

3
เมธอดส่วนขยายจะไม่เกิดขึ้นเมื่อพารามิเตอร์ "แรก" ( thisพารามิเตอร์) เนื่องจากเป็นเพียงแค่น้ำตาลวากยสัมพันธ์ นั่นคือx.SomeExtensionMethod()น้ำตาลที่เป็นประโยคSomeStaticClass.SomeExtensionMethod(x);ด้วยเหตุนี้เมื่อxใดที่nullเราไม่ได้พยายามเรียกใช้วิธีการบนnullวัตถุ แต่เป็นการส่งผ่านnullวัตถุไปยังวิธีการแบบคงที่ ถ้าเมธอดนั้นตรวจหาnullพารามิเตอร์และพ่นเมื่อพบเมธอดส่วนขยายดังกล่าวจะ "เรียก" ในการnullโยนวัตถุ
สัน

7

ฉันไม่เห็นด้วยกับสิ่งนี้:

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

เป็นการแฮ็ก แต่อย่างใด ฉันคิดว่ามันเป็นตัวอย่างที่ดีของรหัสที่ชัดเจน เห็นได้ชัดว่าคุณต้องการบรรลุอะไรและคุณคาดหวังว่าจะเป็นโมฆะ

อัพเดท:

ฉันเห็นแล้วว่าคุณไม่ได้บอกว่านี่เป็นการแฮ็ก แต่โดยนัยในคำถามที่คุณคิดว่าวิธีนี้ไม่ใช่วิธีที่จะไป ในใจของฉันมันเป็นทางออกที่ชัดเจนที่สุด


เขาไม่ได้บอกว่าวิธีนี้แฮ็ค อันที่จริงเขาไม่ได้บอกว่ามีอะไรผิดปกติยกเว้นบางทีบอกเป็นนัยว่ามันไม่ง่าย ฉันไม่คิดว่าจะมีอะไรผิดปกติกับวิธีนี้ +1 เพราะฉันจะทำแบบนี้
Mark Byers

ฉันเห็นด้วยกับ OP ... มีตัวดำเนินการรวมเป็นโมฆะอยู่แล้วใน c # - ดูโพสต์ของฉันด้านล่าง
Andrew Hanlon

ฉันคิดว่าตัวดำเนินการการรวมกันเป็นโมฆะมีความชัดเจนน้อยกว่าเล็กน้อยในกรณีนี้ แต่ฉันก็ใช้ได้เช่นกันเมื่อใช้สิ่งนั้น
steinar

@Pieter พอใช้. แต่มันไม่ คำถามคือ "มีวิธีง่ายๆในการดำเนินการดังต่อไปนี้: ... " วิธีที่แน่นอนนั้นง่ายมาก!
steinar

ฉันไม่เคยกล่าวว่านี้เป็นวิธีการที่สับ โปรดอ่านคำถามของฉันอีกครั้ง ฉันพลาดเพียงฟังก์ชันเล็กน้อยใน Framework ซึ่งมีฟังก์ชันนี้
codymanix

4
string s = String.Concat(myObj);

จะเป็นวิธีที่สั้นที่สุดที่ฉันเดาและยังมีค่าใช้จ่ายด้านประสิทธิภาพที่เป็นลบได้ โปรดทราบว่าผู้อ่านโค้ดจะไม่เข้าใจว่าเจตนาคืออะไร


2
นี่คือรูปแบบที่ชัดเจนของ "" + myObj แต่แย่กว่านั้นในการบอกว่าเกิดอะไรขึ้นที่นี่ น่าสนใจอยู่แล้ว
codymanix

@codymanix ฉันไม่คิดว่ามันเหมือนกัน - Concatจริง ๆ แล้วทำการตรวจสอบค่าว่างข้างใต้และส่งคืนstring.Emptyหรือarg0.ToString()ซึ่งดูเหมือนจะมีประสิทธิภาพมากกว่าเล็กน้อย (ฉันหมายถึงเรากำลังพูดถึง ms ที่นี่)
drzaus

2

ที่จริงฉันไม่เข้าใจว่าคุณต้องการทำอะไร ตามที่ฉันเข้าใจคุณสามารถเขียนโค้ดนี้ด้วยวิธีอื่นเช่นนี้ คุณกำลังถามสิ่งนี้หรือไม่? คุณช่วยอธิบายเพิ่มเติมได้ไหม

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

แน่นอนว่าฉันสามารถเขียนแบบนี้ได้ แต่ฉันต้องการการเรียกใช้ฟังก์ชันขนาดเล็กที่เรียบง่ายฉันสงสัยว่าทำไมไม่มีสิ่งนี้ใน. NET BCL
codymanix

คุณต้องการฟังก์ชันในขณะที่เรามีเมธอด IsNullOrEmpty () หรือไม่?
Serkan Hekimoglu

ในบันทึกนั้นฉันต้องการให้ตัวดำเนินการรวมตัวกันล้มเหลวในครั้งต่อไปเสมอเมื่อมันกระทบการอ้างอิงว่างในนิพจน์ที่คล่องแคล่วของคุณ แต่ฉันเข้าใจดีว่าทำไมมันถึงเป็นความคิดที่แย่มาก การลบล้างที่ช่วยให้คุณทำได้ก็จะดีเช่นกัน
Nick Larsen

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

2

ฉันอาจจะพ่ายแพ้สำหรับคำตอบของฉัน แต่ต่อไปนี้:

ฉันจะเขียน

สตริง s = "" if (myObj! = null) {x = myObj.toString (); }

มีผลตอบแทนในแง่ของประสิทธิภาพสำหรับการใช้ตัวดำเนินการ ternary หรือไม่? ฉันไม่รู้ว่าปิดด้านบนของหัวของฉัน

และเห็นได้ชัดว่าตามที่มีคนกล่าวไว้ข้างต้นคุณสามารถใส่พฤติกรรมนี้ลงในวิธีการเช่น safeString (myObj) ที่อนุญาตให้นำมาใช้ซ้ำได้


OMG ถ้าอ็อบเจกต์เป็นโมฆะให้เรียก ToString () บนมัน?
codymanix

มานั่นเป็นการพิมพ์ผิด ฉันแทนที่ตัวแรก = ด้วย! เพื่อให้ถูกต้อง แต่คุณกำลังจะ -1 ฉันสำหรับการพิมพ์ผิดใช่ไหม
jaydel

2

ฉันมีปัญหาเดียวกันและแก้ไขได้โดยเพียงแค่ส่งวัตถุเป็นสตริง สิ่งนี้ใช้ได้กับอ็อบเจ็กต์ null เช่นกันเนื่องจากสตริงสามารถเป็น null ได้ เว้นแต่คุณไม่ต้องการมีสตริงว่างสิ่งนี้จะใช้ได้ดี:

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

ทางออกที่สั้นและดีที่สุด (Obj1 ?? "") ToString () ครั้งแรกร่าย Obj1 เป็นสตริงด้วย :)
TPAKTOPA

2

การทดสอบประสิทธิภาพ (ความเร็ว) บางรายการสรุปตัวเลือกต่าง ๆ ไม่ใช่ว่าสำคัญจริงๆ #microoptimization (โดยใช้ส่วนขยาย linqpad )

ตัวเลือก

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(...)จะคงสตริงว่างไว้

ผล

วัตถุ

  • nullcheck 1.00x 1221 เห็บที่ผ่านไป (0.1221 ms) [ใน 10K reps, 1.221E-05 ms ต่อ]
  • Coallesce 1.14x 1387 เห็บที่ผ่านไป (0.1387 ms) [ใน 10K reps, 1.387E-05 ms ต่อ]
  • สตริง + 1.16x 1415 เห็บที่ผ่านไป (0.1415 ms) [ใน 10K reps, 1.415E-05 ms ต่อ]
  • str.Concat 1.16x 1420 ขีดที่ผ่านไป (0.142 ms) [ใน 10K reps, 1.42E-05 ms ต่อ]
  • แปลง 1.58x 1931 เห็บที่ผ่านไป (0.1931 ms) [ใน 10K reps, 1.931E-05 ms ต่อ]
  • str.Format 5.45x 6655 เห็บที่ผ่านไป (0.6655 ms) [ใน 10K reps, 6.655E-05 ms ต่อ]

สตริง

  • nullcheck 1.00x 1190 เห็บที่ผ่านไป (0.119 ms) [ใน 10K reps, 1.19E-05 ms ต่อ]
  • แปลง 1.01x 1200 เห็บที่ผ่านไป (0.12 มิลลิวินาที) [ใน 10K reps, 1.2E-05 ms ต่อ]
  • สตริง + 1.04x 1239 เห็บที่ผ่านไป (0.1239 ms) [ใน 10K reps, 1.239E-05 ms ต่อ]
  • Coallesce 1.20x 1423 เห็บที่ผ่านไป (0.1423 ms) [ใน 10K reps, 1.423E-05 ms ต่อ]
  • str.Concat 4.57x 5444 เห็บผ่านไปแล้ว (0.5444 ms) [ใน 10K reps, 5.444E-05 ms ต่อ]
  • str.Format 5.67x 6750 เห็บที่ผ่านไป (0.675 มิลลิวินาที) [ใน 10K reps, 6.75E-05 ms ต่อ]

1

ความคิดเห็นของ Holstebroe จะเป็นคำตอบที่ดีที่สุดของคุณ:

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

ถ้าmyObjเป็นค่าว่างรูปแบบจะวางค่าสตริงว่างไว้ที่นั่น

นอกจากนี้ยังตอบสนองความต้องการหนึ่งบรรทัดของคุณและอ่านง่าย


ใช่ แต่รหัสไม่ชัดเจน เพื่อนนักพัฒนาของคุณกี่คนจะรู้ว่าคุณพยายามทำอะไรให้สำเร็จ
AGuyCalledGerald

0

แม้ว่านี่จะเป็นคำถามเก่าและ OP ขอ C # ฉันต้องการแบ่งปันวิธีแก้ปัญหา VB.Net สำหรับผู้ที่ทำงานกับ VB.Net แทนที่จะเป็น C #:

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

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

โชคไม่ดีที่ VB.Net ไม่อนุญาต? -operator หลังตัวแปรดังนั้น myObj?. ToString จึงไม่ถูกต้อง (อย่างน้อยก็ไม่ใช่ใน. Net 4.5 ซึ่งฉันใช้สำหรับการทดสอบโซลูชัน) แต่ฉันใช้ If เพื่อส่งคืนสตริงว่างในกรณีที่ myObj ist Nothing ดังนั้น Tostring-Call แรกจะส่งคืนสตริงว่างในขณะที่อันที่สอง (โดยที่ myObj ไม่ใช่ Nothing) จะส่งกลับ "42"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.