[英]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.