เหตุใดตัวดำเนินการจึงส่งคืนเท็จเมื่อกำหนดค่าว่าง


136

สำหรับฉันดูเหมือนว่าตัวisดำเนินการจะไม่สอดคล้องกันเล็กน้อย

bool Test()
{
    // Returns false, but should return true.
    return null is string;
}

เราคาดหวังว่าnullค่าเป็นของประเภทการอ้างอิงใด ๆ (หรือเป็นโมฆะ) และแน่นอนข้อกำหนดภาษา C # กล่าวถึงบางสิ่งที่สนับสนุนสมมติฐานนี้เช่น (6.1.6 การแปลงอ้างอิงโดยนัย):

การแปลงอ้างอิงโดยนัยคือ:
...
•จากลิเทอรัลว่างไปเป็นชนิดอ้างอิงใด ๆ

คำอธิบาย (7.10.10 ตัวดำเนินการ is) ของตัวisดำเนินการเริ่มต้นด้วยการบอกว่านิพจน์(E is T)จะส่งผลให้เป็นจริงเมื่อมีการแปลงการอ้างอิงจากEเป็นTมีอยู่ แต่จากนั้นผู้เขียนก็ดำเนินการต่อโดยไม่รวมกรณีที่Eเป็นnullตัวอักษรหรือมีnullค่าอย่างชัดเจน .

ทำไมพวกเขาถึงทำเช่นนั้น? สำหรับฉันแล้วดูเหมือนว่าขัดต่อสัญชาตญาณ


เหตุใดพวกเขาจึงยกเว้น null อย่างชัดเจนจึงเป็นคำถามที่ดีที่สุดสำหรับ programmers.stackoverflow.com
ตัวแปรที่น่าสังเวช

2
ฉันไม่สามารถยกเลิกการโหวตปิดของฉันได้ แต่คำถามเหล่านี้ใช้ได้ที่นี่: meta.stackexchange.com/questions/36850/…
Merlyn Morgan-Graham

ใน java null typeof Objectยังส่งคืนเท็จ
วงล้อประหลาด

สมมติว่าnull is stringเป็นtrueและโดยนัยนี้nullคือไฟล์string. สมมติว่านั่นnull is Nullable<int>คือtrueหมายความว่าnullเป็นไฟล์Nullable<int>. ตอนนี้ตอบคำถามนี้: ประเภทคือnullอะไร?
ผู้ใช้

1
@ Michael Kjörling: ไม่ใช่ sequitur จากข้อเท็จจริงที่กล่าวถึง (null คือสตริง null คือ Nullable <int>) มันไม่เป็นไปตามที่ฉันควรจะสามารถตอบคำถามนั้นได้
Gebb

คำตอบ:


195

คำถามนี้เป็นเรื่องของบล็อกของฉันบน 30 พฤษภาคม 2013 ขอบคุณสำหรับคำถามดีๆ!


คุณกำลังมองไปที่ถนนรถแล่นที่ว่างเปล่า

มีคนถามคุณว่า "รถแล่นของคุณมี Honda Civic ได้ไหม"

ใช่. ใช่มันทำได้

มีคนชี้คุณไปที่ถนนที่สอง มันยังว่างเปล่า พวกเขาถามว่า "เนื้อหาปัจจุบันของถนนรถแล่นของฉันพอดีกับถนนรถแล่นของคุณได้ไหม"

ใช่แน่นอน ถนนทั้งสองว่างเปล่า! เห็นได้ชัดว่าเนื้อหาของหนึ่งสามารถใส่เข้าไปในอีกอันหนึ่งได้เนื่องจากไม่มีเนื้อหาใด ๆ ในตอนแรก

มีคนถามคุณว่า "ถนนของคุณมี Honda Civic หรือไม่"

ไม่มันไม่ได้

คุณกำลังคิดว่าisโอเปอเรเตอร์ตอบคำถามที่สองเมื่อได้รับค่านี้แล้วมันพอดีกับตัวแปรประเภทนั้นหรือไม่? การอ้างอิงค่าว่างพอดีกับตัวแปรประเภทนี้หรือไม่ ใช่.

นั่นไม่ใช่คำถามที่isโอเปอเรเตอร์ตอบ คำถามที่isผู้ดำเนินการตอบคือคำถามที่สาม y is Xไม่ได้ถามว่า " เป็นyค่าทางกฎหมายของตัวแปรประเภทX? " มันถามว่า " คือyการอ้างอิงที่ถูกต้องเพื่อวัตถุประสงค์ของการพิมพ์X? " ตั้งแต่อ้างอิงโมฆะไม่ใช่การอ้างอิงที่ถูกต้องใด ๆของวัตถุใด ๆประเภทคำตอบคือ "ไม่ ". ถนนรถแล่นนั้นว่างเปล่า มันไม่มี Honda Civic

อีกวิธีในการดูคือy is Xตอบคำถาม "ถ้าฉันพูดy as Xไปฉันจะได้ผลลัพธ์ที่ไม่เป็นโมฆะหรือไม่ถ้า y เป็นโมฆะคำตอบคือไม่!


หากต้องการดูคำถามของคุณให้ลึกซึ้งยิ่งขึ้น:

เราคาดหวังว่าค่า null เป็นของประเภทการอ้างอิงใด ๆ (หรือ nullable)

โดยปริยายจะถือว่าประเภทหนึ่งคือชุดของค่าและความเข้ากันได้ของการกำหนดค่า y กับตัวแปรประเภท X นั้นไม่มีอะไรมากไปกว่าการตรวจสอบว่า y เป็นสมาชิกของเซต xหรือไม่

แม้ว่านั่นจะเป็นวิธีที่ใช้กันทั่วไปในการดูประเภท แต่นั่นไม่ใช่วิธีเดียวในการดูประเภทและไม่ใช่วิธีที่ C # ดูประเภท การอ้างอิง Null เป็นสมาชิกที่ไม่มีประเภทใน C #; ความเข้ากันได้รับมอบหมายจะไม่ได้เป็นเพียงการตรวจสอบชุดเพื่อดูว่ามันมีค่า เพียงเพราะการอ้างอิงที่เป็นโมฆะเป็นการกำหนดที่เข้ากันได้กับตัวแปรของการอ้างอิงประเภท X ไม่ได้หมายความว่า null เป็นสมาชิกของประเภท X ความสัมพันธ์ "คือการกำหนดที่เข้ากันได้กับความสัมพันธ์" และความสัมพันธ์ "เป็นสมาชิกประเภท" เห็นได้ชัดว่ามีจำนวน ทับซ้อนกัน แต่ไม่เหมือนกันใน CLR

หากความคิดเกี่ยวกับทฤษฎีประเภทที่คุณสนใจโปรดดูบทความล่าสุดของฉันในหัวข้อ:

สิ่งนี้ที่คุณเรียกว่า "ประเภท" คืออะไร? ส่วนที่หนึ่ง

สิ่งนี้ที่คุณเรียกว่า "ประเภท" คืออะไร? ส่วนที่สอง


@Gebb: ดีใจที่ได้ช่วย บทความนี้อาจเป็นที่สนใจของคุณ: blogs.msdn.com/b/ericlippert/archive/2010/09/16/…
Eric Lippert

Eric เปลี่ยนสิ่งนี้ให้เป็นบล็อกโพสต์: ericlippert.com/2013/05/30/what-the-meaning-of-is-is
Kevin Cathcart

y is Xไม่ถามว่า "เป็นyค่าทางกฎหมายของตัวแปรประเภทXหรือไม่" มันถามว่า " yการอ้างอิงที่ถูกต้องสำหรับวัตถุประเภทXหรือไม่" นั่นคือประเด็นทั้งหมด! ขอบคุณ!
Jalal

แต่ถ้าฉันถามy is int?ฉันจะถามว่า "ทางขับของคุณมี Honda Civic หรือเปล่า" เหตุใดคำตอบจึงยังคงไม่ใช่เมื่อถนนรถแล่นของคุณว่างเปล่า? หากคุณมองใต้ฝากระโปรงมันจะแย่ลงเท่านั้นเนื่องจากคำถามกลายเป็น "ถนนรถแล่นของคุณมี Honda Civic หรือป้ายที่ระบุว่า" No Honda Civic ที่นี่ "หรือไม่" แม้ว่าถนนรถแล่นของคุณจะมีป้ายดังกล่าว แต่คำตอบก็ยังไม่ใช่
แฟกซ์

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

24

ฉันคิดว่าการnull is stringคืนค่าเท็จนั้นใช้งานง่ายมาก Null หมายถึงอะไรและไม่ใช่สตริงแน่นอน ดังนั้นควรคืนค่าเท็จ แม้ว่าจะเป็นตัวเลือกที่นักออกแบบภาษาเลือกใช้ แต่ก็เป็นวิธีที่ใช้งานง่ายมากเมื่อคุณพิจารณาความหมายของโลกแห่งความเป็นโมฆะ


2
+1 เพราะคำถามจริงๆเกี่ยวกับว่ามันใช้งานง่ายและไม่ได้ตั้งคำถามกับสเป็คซึ่ง OP ก็รู้อยู่แล้ว ถ้าคุณถามเป็นประโยคภาษาอังกฤษ "is nulla string" คำตอบคือไม่มันไม่ใช่ซึ่งแตกต่างจาก "is nullstring
assignable

null is stringค่อนข้างใช้งานง่าย(string)null is stringอาจต้องหยุดชั่วคราวหากคุณไม่คุ้นเคยกับวิธีการทำงานของการอ้างอิงว่างใน C #
DecPL

24

ลิเทอnullรัลสามารถกำหนดให้กับประเภทการอ้างอิงใดก็ได้ มันเป็นไม่ได้พิมพ์ของตัวเอง เป็นลิเทอรัลพิเศษที่แสดงถึงการอ้างอิงว่าง

ในกรณีที่isจะกลับมาtrueเมื่อ a nullจะถูกส่งผ่านคุณจะทำอะไรกับnullตัวอักษรได้บ้าง? ไม่มีอะไร - nullมันเป็น อะไรคือจุดที่มันกลับมาtrueยกเว้นเรื่องที่สับสน?


ไม่ว่า - ในแง่ของการใช้งานง่ายเพียงใดอ่านโค้ดเป็นภาษาอังกฤษแล้วบอกฉันว่า:

null is string;

is "nothing" a string?เมื่อผมเห็นว่ามันดูเหมือนว่าจะถามคำถาม สัญชาตญาณของผมบอกว่าไม่มีก็ไม่ได้ - nothingมัน


ไม่เป็นไร แต่มันก็เป็นสตริงด้วยใช่ไหม? แต่ทำไม(null is string)กลับ flase แล้ว?
Gebb

ฉันจะพูดอีกทางหนึ่ง ประเภทการอ้างอิงใด ๆ สามารถเป็นโมฆะ null เป็นเพียงโมฆะ
Mark H

@ ใส่ดังนั้นค่า null จึงเป็นค่าที่ถูกต้องเช่นประเภทวัตถุ? ฉันสามารถกำหนดให้กับตัวแปรประเภทนี้ได้ใช่ไหม ดังนั้นคำตอบดูเหมือนจะใช่ค่านี้ใช้ได้อย่างสมบูรณ์และฉันเดาว่า(null is object)นิพจน์ควรตรวจสอบให้แน่ชัด
Gebb

@Gebb: อย่าลืมว่า ValueTypes เป็นวัตถุเช่นกัน แต่ไม่ใช่ประเภทอ้างอิง
Mark H

1
@Oded: "อะไรคือจุดที่ทำให้มันกลับมาเป็นจริงยกเว้นเรื่องที่สับสน" จริงๆแล้วมันจะทำให้ภาษามีเหตุผลมากขึ้น พิจารณาสองประเด็นนี้: (1) ตัวisดำเนินการตรวจสอบว่ามีการอ้างอิง (เราไม่ต้องการการแปลงประเภทอื่นที่นี่) การแปลงมีอยู่หรือไม่ (2) nullสามารถแปลงเป็นประเภทอ้างอิงใดก็ได้ ดังนั้น(null is T)โดยที่ T เป็นชนิดอ้างอิงควรคืนค่าจริง แต่เปล่าที่นี่เรามีข้อยกเว้นที่ชัดเจนซึ่งเป็นสิ่งที่ทำให้ฉันสับสน
Gebb

12

http://msdn.microsoft.com/en-us/library/scekt9xw%28v=vs.71%29.aspx

นิพจน์ถูกประเมินว่าเป็นจริงหากตรงตามเงื่อนไขทั้งสองต่อไปนี้:

  • นิพจน์ไม่เป็นโมฆะ
  • สามารถส่งนิพจน์ไปพิมพ์ได้ นั่นคือนิพจน์การร่ายของฟอร์ม (ประเภท (นิพจน์) จะเสร็จสมบูรณ์โดยไม่มีข้อยกเว้นสำหรับข้อมูลเพิ่มเติมโปรดดู 7.6.6 นิพจน์การแคสต์

1
อย่างไรก็ตามเอกสารระบุเพียงว่านิพจน์ไม่สามารถเป็นโมฆะได้ (ซึ่งเรารู้อยู่แล้ว) แต่ไม่ได้บอกสาเหตุ
ชื่อผู้ใช้

ทำไมคุณถึงต้องการวิธีอื่น?
ตัวแปรที่น่าสังเวช

1
@ ชื่อผู้ใช้: คำตอบนี้อธิบายถึงวิธีการทำงานของกลไกและอ้างอิงข้อมูลอ้างอิงซึ่งทำให้คุณมีโมเดลที่จะใช้งานได้ คุณกำลังถามความหมายของจักรวาลที่นี่ ฉันเดาว่าคุณโชคดีที่พระเจ้าของเราแวะเวียนเข้ามาดังนั้น)
Merlyn Morgan-Graham

10

ตามความเป็นจริงการมี "null is T == false" ช่วยให้ฉันพิมพ์รหัสพิเศษ:

แทนที่จะต้องพูด

if (X != null && X is Foo) {}

ฉันสามารถพูดได้

if (X is Foo) {}

และทำได้ด้วย


8

nullค่า

ฉันได้ยกมาจากคำถามของคุณเพราะดูเหมือนว่าจะเข้าสู่หัวใจของเรื่องนี้ null ไม่ใช่ค่า - ไม่มีค่า จุดประสงค์ของisฉันดูเหมือนจะตอบคำถาม:

ถ้าฉันส่งEไปTฉันจะได้รับT?

ตอนนี้ในขณะที่คุณสามารถส่งnullไปT โดยไม่มีข้อผิดพลาดหลังจากทำเสร็จแล้วคุณก็ไม่มี "a T" แต่คุณก็ยังไม่มีอะไรเลย ดังนั้นจึงไม่ใช่กรณีที่null"เป็น" a Tดังนั้นจึงisส่งคืนเท็จ


3

ใน Java มีผู้ประกอบการที่ไม่ตรงกับสิ่งเดียวกัน instanceofแต่ก็มีชื่อมากอีกต่อไป: มันใช้งานง่ายมากที่นั่นnull instanceof Stringส่งคืนเท็จเพราะ null ไม่ใช่อินสแตนซ์ของอะไรเลยน้อยกว่าStringมาก ดังนั้นเมื่อใช้nullเวอร์ชันของ Java จึงใช้งานง่ายกว่าเล็กน้อย

อย่างไรก็ตามตัวดำเนินการทั้งสองจะคืนค่าจริงเมื่อถูกขอให้ดูตามลำดับชั้นทั้งหมดด้วย เช่น. หากอินสแตนซ์ของStringเป็นObjectไฟล์. และนี่คือ Java ที่ใช้งานง่ายน้อยกว่าเล็กน้อย (เนื่องจากอินสแตนซ์มีหนึ่งประเภทที่เฉพาะเจาะจงมาก) และ C # isนั้นใช้งานง่ายกว่า (เพราะทุกอย่างString อยู่ในส่วนObjectลึก)

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

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