C # 9 Các vấn đề về kiểu Nullable

Sep 12 2020

Hãy xem xét đoạn mã sau (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 
  }
}

Tôi gặp một sự hiểu biết thời gian khó khăn / giải quyết các sai sót trong F3, Có vẻ như trình biên dịch nghĩ johnAge có longkhông long?(như tôi xác nhận qua lơ lửng trên nó trong VS) bất chấp sự trở lại của Archive<T>.GetAthạnh phúcT?

Có cách nào để có một Kho lưu trữ chung sẽ làm những gì tôi muốn (một phương thức GetAt trả về Nullable ngay cả khi T là kiểu cơ bản không nullable tức là dài)?

Trả lời

8 JonSkeet Sep 12 2020 at 15:13

Về cơ bản, điều này liên quan đến các kiểu giá trị nullable và các kiểu tham chiếu có thể null rất rất khác nhau. CLR biết về các kiểu giá trị nullable, nhưng theo như CLR có liên quan, kiểu tham chiếu nullable chỉ là "kiểu tham chiếu bình thường, với một thuộc tính cho trình biên dịch biết liệu nó có nên được coi là có thể nullable hay không".

Khi Tcó notnullràng buộc, kiểu T?chỉ biên dịch Ttrong IL. Nó phải - nó không thể biên dịch thành Nullable<T>, bởi vì các Nullable<T>ràng buộc Tlà một kiểu giá trị.

Vì vậy, đối với an Archive<long>, GetAtphương thức sẽ trả về 0L nếu khóa không được tìm thấy trong từ điển - nó sẽ không (và không thể) trả về giá trị null của a Nullable<long>, đó là điều mà mã của bạn F3đang mong đợi.

Toàn bộ tính năng "kiểu tham chiếu nullable" bị ảnh hưởng là một nỗ lực để thêm một "phần" của nhận thức có thể vô hiệu lên một hệ thống kiểu về cơ bản không có nó. Tôi chắc chắn nếu một thời gian chạy và ngôn ngữ mới được thiết kế cùng nhau ngay từ đầu, nó sẽ cố gắng thống nhất điều này chặt chẽ hơn. Hiện tại, tôi tin rằng tính năng này vẫn có rất nhiều giá trị - nhưng nó chắc chắn khiến mọi thứ trở nên thực sự phức tạp khi nói đến chung chung.