[英]C#: default of generic T? is not null; behavior changes with generic constraint
我有一個通用類,它應該對(不可為空的)引用和值類型(參數、返回...)進行操作,但內部需要可以為空的字段。
using System;
public class Gen<T> // where T : struct
{
public class Data
{
public T? t;
}
public static void Write(string s)
{
Data d = new Data();
Console.WriteLine("Default of {0} is {1}", s, d.t == null ? "null" : "NOT null");
}
// ... other stuff that uses T and not T? like
// public T DoSomething(T value) ...
}
static class Program
{
static void Main(string[] args)
{
Gen<int>.Write("int?");
Gen<string>.Write("string?");
}
}
在啟用可空值的情況下編譯 (.NET 5) 時,此代碼不會產生任何錯誤或警告。 然而,行為並不像我預期的那樣。
Default of int? is NOT null
Default of string? is null
在尋找解決方案的過程中,我發現當添加where T : struct
約束(並刪除 Gen.Write())時,行為更改為
Default of int? is null
奇怪的是,約束會改變行為。
有人知道編寫這樣一個通用類的優雅解決方案嗎? 使用也支持引用類型的自定義 Nullable 類還是為每個 T 使用單獨的 bool 標志? 歸檔有點乏味。
如果你想使用Nullable<int>
你不應該使用int
,所以使用:
Gen<int?>.Write("int?");
然后輸出將是
Default of int? is null
Default of string? is null
問題中的代碼是一個示例。 真正的類沒有
Write
方法,也從不使用該類型的字符串。 然而,正如我通過“其他東西”所指出的,它使用 T 和 T?。 所以不希望用int?
實例化它int?
而不是int
。
首先我想解釋一下為什么泛型類中的struct
約束改變行為並不奇怪。 因為實際上,如果您是 < C#8,則該約束會使其編譯。 那么T?
表示Nullable<T>
,因此如果您使用Gen<int>.Write("int?")
字段t
將是Nullable<int>
。 但是Gen<string>.Write("string")
根本不會編譯,因為string
不是struct
。 所以它與約束有完全不同的含義。
啟用 C#8 后,您可以刪除struct
約束,然后t
仍然是int
並且string
將是一個可為空的string
。 所以問號的意思是:在引用類型的情況下,它是一個可以為空的引用類型,否則它就是它。
你不能同時擁有一個泛型類型,它可以是一個可以為空的引用類型或一個可以為空的值類型而不使用所需的泛型類型,所以使用int?
如果它必須可以為空。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.