ปัญหาประเภท Nullable กับ?: ผู้ประกอบการตามเงื่อนไข


154

มีคนอธิบายได้ไหมว่าทำไมสิ่งนี้ถึงใช้งานได้ใน C # .NET 2.0:

    Nullable<DateTime> foo;
    if (true)
        foo = null;
    else
        foo = new DateTime(0);

... แต่นี่ไม่ใช่:

    Nullable<DateTime> foo;
    foo = true ? null : new DateTime(0);

แบบฟอร์มหลังทำให้ฉันมีข้อผิดพลาดในการคอมไพล์ "ไม่สามารถระบุชนิดของนิพจน์เงื่อนไขได้เนื่องจากไม่มีการแปลงโดยนัยระหว่าง '<null>' และ 'System.DateTime'

ไม่ใช่ว่าฉันไม่สามารถใช้รูปแบบเดิมได้ แต่รูปแบบที่สองนั้นสอดคล้องกับส่วนที่เหลือของรหัสของฉันมากกว่า


12
คุณสามารถพิมพ์ด้วยตัวเองได้เยอะโดยใช้ DateTime? แทน Nullable <DateTime>
Stewart Johnson

คำตอบ:


325

คำถามนี้ถูกถามมาหลายครั้งแล้ว คอมไพเลอร์กำลังบอกคุณว่ามันไม่รู้ว่าจะแปลงnullเป็นDateTimeอย่างไร

การแก้ปัญหาง่ายมาก:

DateTime? foo;
foo = true ? (DateTime?)null : new DateTime(0);

โปรดทราบว่าNullable<DateTime>สามารถเขียนได้DateTime?ซึ่งจะช่วยให้คุณประหยัดในการพิมพ์


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

@DilbertDave ข้อมูลจากโพสต์ของ MojoFilter ไม่ถูกต้อง
Mishax

4
ฉันจะเพิ่มว่าคอมไพเลอร์พยายามที่จะเดาประเภทผลลัพธ์ของการดำเนินการแบบไตรภาคไม่ใช่โดยดูที่ตัวแปรที่มันถูกกำหนด แต่โดยดูที่ตัวถูกดำเนินการแทน มันค้นหา<null>และDateTimeแทนที่จะค้นหาประเภทบรรพบุรุษร่วมกันมันแค่พยายามหาการแปลงระหว่างกันและกัน (บิตพิเศษ: C # รับรู้<null>ประเภทคือประเภทของทุกnullนิพจน์)
IllidanS4 ต้องการโมนิก้าย้อนกลับ

หากมีการถามหลายครั้งแล้วแฟล็กคำถามซ้ำกันอยู่ที่ไหน
starmandeluxe

@starmandeluxe พวกเขามีแนวโน้มที่จุดทั้งหมดที่นี่ (อย่างน้อยที่ผมว่าผมนี่)
สกอตต์แชมเบอร์เลน

19

FYI (Offtopic แต่ดีและเกี่ยวข้องกับประเภท nullable) เรามีโอเปอเรเตอร์ที่ใช้งานง่ายสำหรับประเภท nullable ที่เรียกว่าตัวดำเนินการรวมศูนย์ว่าง

??

ใช้แบบนี้:

// Left hand is the nullable type, righthand is default if the type is null.
Nullable<DateTime> foo;
DateTime value = foo ?? new DateTime(0);

9
คำถามนี้ตอบคำถามของเขาอย่างไร?
Stewart Johnson

3
Nick พยายามกำหนด null ให้กับ foo ถ้าเงื่อนไขบางอย่างเป็นจริง การรวมกันเป็นโมฆะจะกำหนด DateTime (0) ให้กับค่าถ้า foo เป็นโมฆะ ทั้งสองไม่เกี่ยวข้องอย่างสมบูรณ์
Jeromy Irvine

4
ดังนั้น FYI, offtopic แต่เป็นสิ่งที่ดีที่จะรู้
FlySwat

อาโอเค. มันค่อนข้างมีประโยชน์ที่จะรู้
Jeromy Irvine

8

เป็นเพราะในผู้ประกอบการที่ประกอบไปด้วยสามค่าจะต้องแก้ไขให้เป็นประเภทเดียวกัน


10
ไม่พวกเขาไม่จำเป็นต้องเป็นคนประเภทเดียวกัน ตัวถูกดำเนินการตัวที่สองจะต้องสามารถแปลงได้โดยปริยายเป็นชนิดของตัวถูกดำเนินการตัวที่สามหรืออย่างอื่น
Mishax

3

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

สิ่งแรกคือการทำให้ null เข้ากันได้กับ DateTime (ตัวอย่างเช่นส่งค่า null เป็น DateTime? ในฐานะสุภาพบุรุษที่มี 70 upvotes แนะนำหรือใช้ null เป็น Object หรือ ValueType)

ที่สองคือการทำให้ DateTime เข้ากันได้กับ null (เช่น Cast DateTime ถึง DateTime?)


3

โซลูชันอื่นที่คล้ายกับที่ยอมรับคือการใช้defaultคำหลักของ C # ในขณะที่กำหนดโดยใช้ generics จริง ๆ แล้วมันสามารถใช้กับทุกประเภท

ตัวอย่างการใช้งานที่ใช้กับคำถามของ OP:

Nullable<DateTime> foo;
foo = true ? default(DateTime) : new DateTime(0);

ตัวอย่างการใช้งานกับคำตอบที่ยอมรับในปัจจุบัน:

DateTime? foo;
foo = true ? default(DateTime) : new DateTime(0);

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

DateTime foo;
foo = true ? default(DateTime) : new DateTime(0);

13
ไม่เป็นความจริงdefault(DateTime)ไม่ได้เป็นโมฆะมันคือ " 1.1.0001 0:00:00" new DateTime(0)เช่นเดียวกับ
IllidanS4 ต้องการโมนิก้ากลับ

@ IllidanS4 ฉันไม่ได้บอกว่ามันมีค่าเท่ากับnullโดยการใช้default()คุณสามารถกำหนดให้กับnullableค่า (ตามสถานะ MSDN) ตัวอย่างที่ผมแสดงให้เห็นถึงความเก่งกาจที่ว่ามันสามารถใช้กับNullable<DateTime>, และก็DateTime? DateTimeหากคุณเชื่อว่าสิ่งนี้ไม่ถูกต้องคุณสามารถระบุ PoC ที่สิ่งเหล่านี้ล้มเหลวได้หรือไม่?
เฟอร์นิเจอร์ใหม่

3
ผู้ถามต้องการเก็บไว้nullในตัวแปรไม่ใช่default(DateTime)ดังนั้นนี่เป็นการหลอกลวงที่ดีที่สุด นี่ไม่ใช่ "เอนกประสงค์" ตามที่คุณบ่งบอกเนื่องจากการแสดงออกโดยรวมยังคงเป็นประเภทเดียวกัน - DateTimeและคุณสามารถแทนที่default(DateTime)ด้วยnew DateTime()และมันจะทำในสิ่งเดียวกัน อาจจะเป็นสิ่งที่คุณหมายเนื่องจากว่าเป็นจริงเท่ากับdefault(DateTime?) null
IllidanS4 ต้องการโมนิก้ากลับ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.