简体   繁体   中英

C# 9 Nullable types issues

Consider the following (VS 16.8.0 Preview 2.1 C# 9.0 preview) code:

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

I am having a hard time understanding/addressing the errors in F3, Seems like the compiler thinks johnAge there is long not long? (as I verified by hovering over it in VS) despite the return of Archive<T>.GetAt being T?

Is there a way to have a generic Archive which will do what I want (a GetAt method that return Nullable even when T is a non nullable basic type ie long) ?

Fundamentally, this comes down to nullable value types and nullable reference types being very, very different. The CLR is aware of nullable value types, but as far as the CLR is concerned, nullable reference types are just "the normal reference type, with an attribute telling the compiler whether or not it should be considered as nullable".

When T has the notnull constraint, the type T? just compiles to T in the IL. It has to - it can't compile to Nullable<T> , because Nullable<T> constraints T to be a value type.

So for an Archive<long> , the GetAt method will return 0L if the key isn't found in the dictionary - it won't (and can't) return the null value of a Nullable<long> , which is what your code in F3 is effectively expecting.

The whole "nullable reference types" feature suffers from being an attempt to add a "veneer" of nullable awareness over a type system that fundamentally doesn't have it. I'm sure if a new runtime and language were being designed together from scratch now, it would try to unify this more closely. As it is, I believe the feature still has a lot of value - but it definitely makes things really tricky when it comes to generics.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM