C # 9 ปัญหาประเภท Nullable

Sep 12 2020

พิจารณาโค้ดต่อไปนี้ (VS 16.8.0 Preview 2.1 C # 9.0 preview):

#nullable enable

using System.Collections.Generic;

class Archive<T> where T : notnull 
{
  readonly Dictionary<string, T> Dict = new();

  public T? GetAt(string key) 
  { 
    return Dict.TryGetValue(key, out var value) ? value : default;
  }
}

class Manager 
{
  public int Age { get; set; }
}

class Main34 
{
  long F3() 
  {
    Archive<long> a = new();
    var johnAge = a.GetAt("john");
    if (johnAge is null) return -1; // Error CS0037  Cannot convert null to 'long' because it is a non - nullable value type
    return johnAge; 
  }

  long F4() 
  {
    Archive<Manager> a = new();
    var johnAge = a.GetAt("john");
    //if (johnAge is null) return -1;
    return johnAge.Age; // Correct ! warning "Derefrencing of a possibly null reference" will be removed if line above unremarked 
  }
}

ฉันกำลังมีความเข้าใจเวลาที่ยาก / ที่อยู่ข้อผิดพลาดใน F3, ดูเหมือนว่าคอมไพเลอร์คิด johnAge มีlongไม่ได้long?(ที่ผมตรวจสอบโดยโฉบเหนือใน VS) แม้จะมีการกลับมาของArchive<T>.GetAtความเป็นอยู่T?

มีวิธีใดบ้างที่จะมีไฟล์เก็บถาวรทั่วไปซึ่งจะทำสิ่งที่ฉันต้องการ (วิธี GetAt ที่คืนค่า Nullable แม้ว่า T จะเป็นประเภทพื้นฐานที่ไม่เป็นโมฆะเช่น long)

คำตอบ

8 JonSkeet Sep 12 2020 at 15:13

โดยพื้นฐานแล้วสิ่งนี้มาจากประเภทค่าที่เป็นโมฆะและประเภทการอ้างอิงที่เป็นโมฆะซึ่งแตกต่างกันมาก CLR ตระหนักถึงประเภทค่าที่เป็นโมฆะ แต่เท่าที่เกี่ยวข้องกับ CLR ประเภทการอ้างอิงที่เป็นโมฆะเป็นเพียง "ประเภทการอ้างอิงปกติโดยมีแอตทริบิวต์บอกคอมไพลเลอร์ว่าควรพิจารณาว่าเป็นโมฆะหรือไม่"

เมื่อTมีnotnullข้อ จำกัด ประเภทT?จะรวบรวมTใน IL มันต้อง - มันไม่สามารถคอมไพล์ได้Nullable<T>เนื่องจากมีNullable<T>ข้อ จำกัดTในการเป็นประเภทค่า

ดังนั้นการArchive<long>ที่GetAtวิธีการที่จะกลับ 0L ถ้าคีย์ไม่พบในพจนานุกรม - มันจะไม่ (และไม่สามารถ) กลับค่า null ของNullable<long>ซึ่งเป็นสิ่งที่รหัสของคุณในF3อย่างมีประสิทธิภาพคาดหวังว่า

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