Проблемы с типами, допускающими значение NULL, в C# 9

Рассмотрим следующий код (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 является базовым типом, не допускающим значения NULL, т.е. long)?

1 ответ

Решение

По сути, это сводится к тому, что типы значений, допускающие значение NULL, и ссылочные типы, допускающие значение NULL, очень, очень разные. CLR знает о типах значений, допускающих значение NULL, но, что касается CLR, ссылочные типы, допускающие значение NULL, являются просто "нормальным ссылочным типом с атрибутом, который сообщает компилятору, следует ли считать его допускающим значение NULL".

когда T имеет notnull ограничение, тип T? просто компилируется в Tв Ил. Он должен - он не может компилироваться в Nullable<T>, потому как Nullable<T> ограничения T быть типом значения.

Так что для Archive<long>, то GetAtметод вернет 0L, если ключ не найден в словаре - он не будет (и не может) вернуть нулевое значение Nullable<long>, это то, что ваш код в F3 эффективно ожидает.

Вся функция "ссылочных типов, допускающих значение NULL" страдает от попытки добавить "видимость" поддержки значений NULL в системе типов, в которой ее в принципе нет. Я уверен, что если бы новая среда выполнения и язык разрабатывались вместе с нуля, они попытались бы объединить это более тесно. Как бы то ни было, я считаю, что эта функция по-прежнему имеет большую ценность, но определенно делает вещи действительно сложными, когда дело доходит до дженериков.

Другие вопросы по тегам