string. ว่างเปล่า vs null คุณใช้อันไหน?


85

เมื่อเร็ว ๆ นี้เพื่อนร่วมงานในที่ทำงานบอกฉันว่าอย่าใช้string.Emptyเมื่อตั้งค่าตัวแปรสตริง แต่ใช้nullในขณะที่มันก่อมลพิษในสแต็ก?

เขาบอกว่าอย่าทำ

string myString=string.Empty; แต่ทำ string mystring=null;

มันสำคัญจริงหรือ? ฉันรู้ว่าสตริงเป็นวัตถุดังนั้นมันจึงสมเหตุสมผล

ฉันรู้ว่าเป็นคำถามโง่ ๆ แต่มุมมองของคุณคืออะไร?


1
ฉันไม่แน่ใจทั้งหมดว่าทำไมคุณถึงทำเช่นนั้น ... คุณสามารถยกตัวอย่างโค้ดที่คุณกำลังพูดถึงอีกเล็กน้อยได้หรือไม่?
stusmith

ไม่มีรหัสฉันขอให้เพื่อนร่วมงานของฉันดูบางสิ่งที่ฉันกำลังดีบักและเขาบอกว่าเป็นกฎทั่วไป "อย่าใช้ string.empty" ตั้งค่าเป็นโมฆะเมื่อมันไปบนสแต็กโดยส่วนตัวแล้วฉันใช้สตริงมาตลอดว่างเปล่า เมื่อถึงเวลาที่มันควรจะเป็นสิ่งที่ถูกต้องในการใช้งานมากกว่า ""
user712923


สิ่งที่ผมหมายถึงคือ ... string.Empty, ""และnullเป็นค่าคงที่ทั้งหมด แต่พวกเขากำลังทั้งหมด 'ง่าย' พอที่ฉันไม่สามารถดูว่าทำไมคุณต้องการกำหนดหนึ่งให้กับตัวแปร หากคุณต้องการจับoutตัวแปรทำไมไม่ใช้string myString;?
stusmith

8
ทุกวันนี้ข้อโต้แย้งในหัวข้อเช่นนี้ที่ไม่ได้เน้นไปที่ความสามารถในการอ่านและความหมายและการมุ่งเน้นไปที่การเพิ่มประสิทธิภาพไมโครที่ไร้สาระนั้นอ่อนแอที่สุด ใช้ข้อใดก็ได้ที่หมายถึงสิ่งที่ถูกต้องสำหรับบริบทที่คุณกำหนด (เช่นถ้าคุณรู้จักใครสักคนที่ไม่มีชื่อกลางให้ใช้String.Emptyถ้าคุณไม่รู้ว่ามีคนใช้ชื่อกลางหรือไม่null) จากนั้นเมื่อคุณมีความหมายที่ถูกต้องแล้วให้เขียนโค้ดด้วยวิธีที่ถูกต้องชัดเจนและดูแลรักษาได้ง่าย
สัน

คำตอบ:


111

nullและEmptyแตกต่างกันมากและฉันไม่แนะนำให้สลับระหว่างกันโดยพลการ แต่ไม่มี "ต้นทุน" เพิ่มเติมใด ๆ เนื่องจากEmptyเป็นการอ้างอิงคงที่เพียงครั้งเดียว (คุณสามารถใช้ได้กี่ครั้งก็ได้)

ไม่มี "มลพิษ" บนกองที่เกิดจากldsfld - ความกังวลนั้น .... บ้า การโหลดnullเนื้อหามีราคาถูกกว่าเล็กน้อยแต่อาจทำให้เกิดข้อยกเว้นการอ้างอิงที่เป็นโมฆะหากคุณไม่ระมัดระวังในการตรวจสอบค่า

โดยส่วนตัวฉันไม่ใช้ทั้งสองอย่าง ... ถ้าฉันต้องการสตริงว่างฉันใช้""- เรียบง่ายและชัดเจน Interning หมายความว่าสิ่งนี้ไม่มีค่าใช้จ่ายต่อการใช้งาน


ที่ระดับ IL ความแตกต่างระหว่าง "" และ Empty เป็นเพียง ldstr เทียบกับ ldsfld - แต่ทั้งสองให้การอ้างอิงสตริงภายในเดียวที่เหมือนกัน นอกจากนี้ใน. NET เวอร์ชันล่าสุด JIT ยังมีการสกัดกั้นโดยตรงซึ่งทำให้การอ้างอิงสตริงว่างเปล่าโดยไม่ต้องทำการค้นหาฟิลด์แบบคงที่ โดยพื้นฐานแล้วไม่มีเหตุผลที่จะต้องสนใจทั้งสองวิธียกเว้นความสามารถในการอ่าน ฉันแค่ใช้ ""


5
@ user712923 ถ้าเขากลับมาพร้อมกับความกังวลที่เป็นรูปธรรมฉันชอบที่จะได้ยินพวกเขา
Marc Gravell

4
@Marc: ASAIK "" สร้างวัตถุที่ string.Empty ไม่ได้เป็น .. ตรวจสอบนี้และนี้ มีบางอย่างที่เกี่ยวข้องกับสระว่ายน้ำฝึกหัดสตริง ....
Jalal กล่าว


1
+1 สำหรับใช้""แทนรหัสสำเร็จรูปที่ยาวขึ้นหกเท่า ใครที่สนับสนุนเรื่องไร้สาระนี้?! @Jalal การโพสต์ของ Brad Abrams นั้นล้าสมัยอย่างมากและหากคอมไพเลอร์ยังคงไม่ปรับให้รหัสทั้งสองนี้ทำสิ่งเดียวกันให้เกิดความอับอายใน Microsoft! แต่ไม่ใช่หน้าที่ของเราที่จะแก้ไขงานของพวกเขา และในความเป็นจริงเราไม่จำเป็นต้อง: ในลิงค์ที่สอง Lasse (ในความคิดเห็น) ได้เปรียบเทียบผลลัพธ์การประกอบของการเปรียบเทียบกับตัวแปรใดตัวแปรหนึ่ง: เหมือนกัน
Konrad Rudolph

1
@ Konrad: ตัวอย่างหนึ่งคือสิ่งที่เกิดขึ้นเมื่อเชื่อมต่อสตริงคงที่: คลาสสตริงใช้พูลภายในดังนั้นเมื่อคุณสร้างสตริงใหม่คลาสจะตรวจสอบว่าสตริงนั้นอยู่ในพูลแล้วหรือไม่หากไม่ได้เพิ่มลงในพูล .. ด้วยเหตุนี้เมื่อ""มันจะค้นหาพูลทั้งหมดเพื่อตรวจสอบว่ามีอยู่แล้วหรือไม่และนั่นเป็นวิธีที่เมื่อใช้string.Empty;มันจะใช้ค่าที่กำหนดไว้ล่วงหน้าและการค้นหาจะไม่มีอยู่อีกต่อไป ชั้นเรียนยังเปิดเผยวิธีการนี้: string.Intern/IsInternedตรวจสอบสิ่งนี้
Jalal Said

35

มันไม่ได้ 'ก่อให้เกิดมลพิษในสแต็ค' ไม่มีเหตุผลทางเทคนิค แต่มีความแตกต่างอย่างมากระหว่างการตั้งค่าตัวแปรเพื่ออ้างอิงถึงวัตถุ (แม้ว่าจะเป็นสตริงว่างnullก็ตาม) และ. ไม่ใช่สิ่งเดียวกันและควรใช้ในรูปแบบที่แตกต่างกัน

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

แก้ไขเพิ่มตัวอย่าง:

  • คุณอาจใช้string.Emptyเป็น postfix เริ่มต้นสำหรับชื่อบุคคล (คนส่วนใหญ่ไม่มีปริญญาเอกเช่น)

  • คุณอาจใช้nullสำหรับตัวเลือกการกำหนดค่าที่ไม่ได้ระบุไว้ในไฟล์กำหนดค่า ในกรณีนี้string.Emptyจะถูกใช้หากมีตัวเลือก config แต่ค่าที่กำหนดค่าที่ต้องการคือสตริงว่าง


ฉันไม่เคยคิดแบบนั้นฉันต้องยอมรับจากสิ่งที่คุณเพิ่งพูดคุณช่วยยกตัวอย่างให้ฉันได้ไหมฉันรู้ว่าคำอธิบายของคุณอธิบายตัวเองได้ แต่ก็ยัง ... ขอบคุณ
user712923

2
เหตุผลเดียวที่ต้องเลือกอย่างใดอย่างหนึ่งขึ้นอยู่กับสถานที่ที่คุณจะใช้ เช่นใช้string.Emptyหรือ""เมื่อคุณต้องการใช้สตริงว่างและnullเมื่อคุณต้องการระบุว่าไม่มีข้อมูล คุณอาจใช้string.Emptyเป็น postfix เริ่มต้นสำหรับชื่อบุคคล (คนส่วนใหญ่ไม่มีปริญญาเอกเช่น) และnullสำหรับตัวเลือกการกำหนดค่าที่ไม่ได้ระบุไว้ในไฟล์กำหนดค่า ในกรณีที่สองนั้นstring.Emptyจะถูกใช้หากมีตัวเลือกการกำหนดค่า แต่ค่าที่กำหนดค่าที่ต้องการคือสตริงว่าง
Kieren Johnstone

@Kieren Johnstone ถ้าไม่มีชื่อ postfix ทำไมไม่ใช้nullเพื่อระบุว่า "no postfix"?
OfirD

8

พวกเขาแตกต่างกันตามที่คนอื่นตอบไปแล้ว

static void Main(string[] args)
{
    string s1 = null;
    string s2 = string.Empty;
    string s3 = "";
    Console.WriteLine(s1 == s2);
    Console.WriteLine(s1 == s3);
    Console.WriteLine(s2 == s3);
}

 results:
 false     - since null is different from string.empty
 false     - since null is different from ""
 true      - since "" is same as string.empty

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

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

เซ็กเมนต์ 1 - ข้อมูลเมตาซึ่งเก็บไว้ใน 1 ไบต์และอธิบายความยาวของเซ็กเมนต์ถัดไป

เซ็กเมนต์ 2 - เก็บความยาวของสตริงที่จะบันทึก

ตัวอย่าง:
string "abcd" - เพื่อให้ง่ายขึ้นฉันจะแปลงโดยใช้ตัวเข้ารหัส ASCII และจะได้รับ {65,66,67,68}
คำนวณเซ็กเมนต์ 2 จะได้ผลลัพธ์ 4 - ดังนั้น 4 ไบต์คือความยาวของสตริงที่แปลงแล้ว
คำนวณเซ็กเมนต์ 1 จะให้ผล 1 - เนื่องจากใช้เพียง 1 ไบต์เพื่อเก็บข้อมูลความยาวของข้อมูลสตริงที่แปลงแล้ว (ซึ่งเป็น 4 เช่นถ้าเป็น 260 ฉันจะได้ 2)

แถบใหม่ของไบต์ตอนนี้จะเป็น {1,4,65,66,67,68} ซึ่งสามารถบันทึกลงในไฟล์ได้

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

มีประโยชน์มากขึ้นเช่นการทราบขนาดที่จะโหลดหรือสะสมหากคุณกระตุกหลายสตริง

กลับไปที่หัวเรื่อง - มันจะ .. ก่อให้เกิดมลพิษในสแต็กเนื่องจากหลักการเดียวกันที่อธิบายไว้ถูกใช้โดยระบบใด ๆ เพื่อแยกความแตกต่างของ null จากว่างเปล่า .. ดังนั้นใช่สตริงการว่างจะใช้หน่วยความจำมากกว่า null แม้ว่าฉันจะไม่ เรียกมันว่ามลพิษ .. มันเพิ่มขึ้นเพียง 1 ไบต์


1

ได้รับคำตอบว่าเป็นความตาย แต่ null หมายถึงไม่มีค่าไม่ได้กำหนดค่าเริ่มต้น string.Empty หมายถึง "" (สตริงว่าง) ตามที่ระบุไว้ใน MSDN

วิธีที่ปลอดภัยที่สุดในการตรวจสอบสตริงว่างหรือ null คือการใช้ string.IsNullOrEmpty


-2

FWIW ฉันพบว่าการผสม""และString.Emptyไม่ทำงาน:

var a = "";
alert("a " + (a == "") + ", " + (a==String.Empty));   //Yields "a true, false"

var b = String.Empty;
alert("b " + (b == "") + ", " + (b == String.Empty)); //Yields "b false, true"

โดยเฉพาะอย่างยิ่งถ้าคุณใช้$.trimจะได้รับค่าของช่องใส่ DOM ที่ว่างเปล่าแล้วเปรียบเทียบกับคุณจะได้รับString.Empty falseไม่แน่ใจว่าทำไมถึงเป็นเช่นนั้น แต่คุณไปแล้ว ตอนนี้ฉันใช้""ทุกที่เพื่อความสม่ำเสมอ


1
ใช่. นี่คือเหตุผลที่เราทุกคนควรรักษานิสัยในการตรวจสอบ.Length==0หรือใช้.Compare()
zanlok

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