Nullable <int> เทียบกับ int? - มีความแตกต่างหรือไม่?


94

เห็นได้ชัดNullable<int>และint?มีมูลค่าเทียบเท่า มีเหตุผลใดบ้างที่ต้องเลือกอย่างใดอย่างหนึ่ง?

Nullable<int> a = null;
int? b = null;
a == b; // this is true

คำตอบ:


135

ไม่แตกต่าง.

int?เป็นเพียงชวเลขที่ตัวเองเป็นชวเลขNullable<int>Nullable<Int32>

โค้ดที่คอมไพล์จะเหมือนกับโค้ดที่คุณเลือกใช้


1
น่าเสียดายที่มีบางกรณีที่ไม่เป็นความจริงอย่างเคร่งครัด ดูคำตอบนี้
qqbenq

22

?แบบฟอร์มการจดชวเลขเป็นเพียงสำหรับชนิดเต็มรูปแบบ ความชอบส่วนบุคคลเป็นเหตุผลเดียวที่จะเลือกอย่างใดอย่างหนึ่ง

รายละเอียดที่นี่

ไวยากรณ์T?เป็นชวเลข Nullable<T>โดยที่Tประเภทค่า ทั้งสองรูปแบบสามารถใช้แทนกันได้


18

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

void Test<T>(T a, bool b)
{
    var test = a is int? & b;              // does not compile
    var test2 = a is Nullable<int> & b;    // does compile
}

บรรทัดแรกแสดงข้อความแสดงข้อผิดพลาดต่อไปนี้:

error CS1003: Syntax error, ':' expected 
error CS1525: Invalid expression term ';'

หากคุณสงสัยเกี่ยวกับเหตุผลที่แท้จริงสำหรับสิ่งนี้ฉันขอแนะนำให้คุณตรวจสอบคำถามที่เชื่อมโยงอยู่แล้วแต่ปัญหาพื้นฐานคือในขั้นตอนการแยกวิเคราะห์หลังจากตัวดำเนินการis(หรือตัวas) เมื่อเราเผชิญหน้ากับ?โทเค็นเราจะตรวจสอบว่าถัดไปโทเค็นสามารถตีความได้ว่าเป็นตัวดำเนินการยูนารี ( &อาจเป็นหนึ่งตัว) และถ้าเป็นเช่นนั้น: ตัวแยกวิเคราะห์ไม่สนใจเกี่ยวกับความเป็นไปได้ที่?โทเค็นจะเป็นตัวปรับเปลี่ยนประเภทเพียงแค่ใช้ประเภทก่อนหน้านั้นและจะแยกวิเคราะห์ส่วนที่เหลือราวกับว่า?โทเค็นเป็นตัวดำเนินการที่เกี่ยวข้อง (ดังนั้นการแยกวิเคราะห์จะล้มเหลว)

ดังนั้นในขณะที่โดยทั่วไปint?และNullable<int>สามารถใช้แทนกันได้มีบางกรณีที่ให้ผลลัพธ์ที่แตกต่างกันโดยสิ้นเชิงเนื่องจากการที่โปรแกรมแยกวิเคราะห์เห็นรหัสของคุณ


2
กรณีแรกคือการแก้ไขด้วยวงเล็บดังนั้นtest var test = (a is int?) & b;นอกจากนี้ยังสามารถแก้ไขด้วยvar test = a is int? && b;และระบุว่าbเป็นค่าพารามิเตอร์ง่าย (ไม่มีผลข้างเคียงกับการประเมินผล) มันดูเหมือนว่าแปลกที่จะชอบมากกว่า& &&
Jeppe Stig Nielsen

ในไวยากรณ์เฉพาะ?นั้นเป็นอักขระหลัก
Pete Garafano

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

เจ๊เป้ถูกต้อง ไม่ใช่การคอมไพล์เนื่องจากกำลังตีความint?ว่าเป็นการดำเนินการ ternary ( var test = a is int? <return if true> : <return if false>) ไม่ใช่ int ที่เป็นโมฆะ
Levi Fuller

1
@LeviFuller (ต่อ)ดูเอกสารสำหรับการboolโอเวอร์โหลดโดยเฉพาะเหล่านี้ เหล่านี้คือตัวดำเนินการตรรกะบูลีน ( &สำหรับbool) และตัวดำเนินการตรรกะแบบมีเงื่อนไขบูลีน ( &&สำหรับbool) สังเกตว่าส่วนย่อยแรกเหล่านี้ตั้งชื่ออย่างชัดเจนว่าตรรกะอย่างไร โปรดจำไว้ว่าใน C # ไม่มีการแปลง ("ร่าย") ระหว่างboolและประเภทตัวเลข!
Jeppe Stig Nielsen

6

เห็นได้ชัดว่ามีความแตกต่างระหว่างทั้งสองเมื่อใช้การสร้าง Entity Framework (EF) แรกของโค้ด:

เมื่อเอนทิตีของคุณมีคุณสมบัติที่ประกาศเช่น:

public class MyEntity
{
    public Nullable<int> MyNullableInt { get; set; } 
}

EF จะไม่สร้างคุณสมบัติที่เป็นโมฆะและคุณจะต้องบังคับให้เครื่องกำเนิดไฟฟ้าทำให้เป็นโมฆะดังนี้:

public class YourContext : DbContext
{
    public DbSet<MyEntity> MyEntities{ get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<MyEntity>().Property(x => x.MyNullableInt).IsOptional();
    }
}

ในทางกลับกันหากคุณประกาศนิติบุคคลของคุณเช่น:

public class MyEntity
{
     public int? MyNullableInt { get; set; }
}

ตัวสร้าง EF จะสร้างคุณสมบัติที่เป็นโมฆะพร้อมกับฟิลด์ที่ว่างเปล่าในตารางฐานข้อมูลที่เกี่ยวข้อง


2
นั่นเป็นเรื่องที่โชคร้ายจริงๆ
siride

8
นั่นแสดงว่าคุณมีNullableคำจำกัดความอื่น ๆอยู่ที่ไหนสักแห่งเพราะในตัวNullable<T>มันเป็นไปไม่ได้ที่ EF จะเห็นความแตกต่างระหว่างทั้งสอง แม้ว่าคน EF จะต้องการปฏิบัติต่อพวกเขาอย่างแตกต่างกัน แต่ก็ทำไม่ได้

1
มีคนยืนยันว่าเป็นกรณีนี้หรือไม่? (ระวังนิดนึงเพราะคะแนนโหวตลบ)
RayLoveless

@RayL ไม่ใช่กรณีนี้ คำตอบนี้ไม่ถูกต้องและตามที่ hvd ชี้ให้เห็นเป็นไปไม่ได้
รองเท้า

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

2

Nullableเป็นประเภททั่วไป แต่int? ไม่ใช่.

มีบางสถานการณ์ที่ควรใช้Nullableกับint?

เช่น: ที่นี่คุณไม่สามารถแทนที่Nullableด้วยint?

คุณจะเปลี่ยนรหัสด้านล่างโดยไม่ใช้Nullable ได้อย่างไร?

class LazyValue<T> where T : struct
{
   private Nullable<T> val;
   private Func<T> getValue;

   // Constructor.
   public LazyValue(Func<T> func)
   {
      val = null;
      getValue = func;
   }

   public T Value
   {
      get
      {
         if (val == null)
            // Execute the delegate.
            val = getValue();
         return (T)val;
      }
   }
}

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