C # 9 Problemi sui tipi nullable

Sep 12 2020

Considerare il codice seguente (anteprima per VS 16.8.0 Preview 2.1 C # 9.0):

#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 
  }
}

Sto attraversando un momento difficile comprensione / affrontando gli errori in F3, Sembra che il compilatore pensa johnAge c'è longnon long?(come ho verificato dal bilico su di esso in VS), nonostante il ritorno di Archive<T>.GetAtessereT?

C'è un modo per avere un archivio generico che farà quello che voglio (un metodo GetAt che restituisce Nullable anche quando T è un tipo di base non annullabile cioè lungo)?

Risposte

8 JonSkeet Sep 12 2020 at 15:13

Fondamentalmente, questo si riduce a tipi di valore nullable e tipi di riferimento nullable che sono molto, molto diversi. Il CLR è a conoscenza dei tipi di valore nullable, ma per quanto riguarda il CLR, i tipi di riferimento nullable sono semplicemente "il tipo di riferimento normale, con un attributo che dice al compilatore se deve o meno essere considerato come nullable".

Quando Tha il notnullvincolo, il tipo viene T?compilato Tin IL. Deve - non può essere compilato Nullable<T>, perché i Nullable<T>vincoli Tdevono essere un tipo di valore.

Quindi per an Archive<long>, il GetAtmetodo restituirà 0L se la chiave non viene trovata nel dizionario: non (e non può) restituire il valore nullo di a Nullable<long>, che è ciò che il codice in realtà siF3 aspetta.

L'intera funzionalità "tipi di riferimento nullable" soffre di essere un tentativo di aggiungere un "rivestimento" di consapevolezza nullable su un sistema di tipi che fondamentalmente non lo dispone. Sono sicuro che se un nuovo runtime e un nuovo linguaggio venissero progettati insieme da zero ora, proverebbe a unificarli più da vicino. Così com'è, credo che la funzione abbia ancora molto valore, ma sicuramente rende le cose davvero complicate quando si tratta di generici.