C#9Nullable型の問題
次の(VS16.8.0プレビュー2.1C#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
}
}
F3のエラーを理解/対処するのに苦労しています。コンパイラはlong、long?(VSでホバーして確認したように)johnAgeが存在しないと考えArchive<T>.GetAtているようです。T?
私が望むことを実行する汎用アーカイブを作成する方法はありますか(Tがnull許容ではない基本型、つまりlongの場合でもNullableを返すGetAtメソッド)?
回答
基本的に、これはnull許容値型とnull許容参照型が非常に異なることになります。CLRはnull許容値型を認識しますが、CLRに関する限り、null許容参照型は「通常の参照型であり、コンパイラにnull許容と見なすべきかどうかを示す属性があります」。
に制約Tがあるnotnull場合、型はILでT?コンパイルさTれるだけです。制約は値型であるNullable<T>ため、コンパイルできません。Nullable<T>T
したがって、の場合、キーがディクショナリに見つからない場合Archive<long>、GetAtメソッドは0Lを返します-コードが効果的に期待しているものである、のnull値を返しません(そして返すことができません)。Nullable<long>F3
「null許容参照型」機能全体は、基本的にそれを持たない型システム上にnull許容認識の「ベニア」を追加しようとする試みに悩まされています。新しいランタイムと言語が今ゼロから一緒に設計されていたとしたら、これをより緊密に統合しようとするでしょう。現状では、この機能にはまだ多くの価値があると思いますが、ジェネリックに関しては間違いなく非常に注意が必要です。