【发布时间】:2019-09-22 07:39:44
【问题描述】:
我想创建一个具有T 类型成员的泛型类。 T 可以是类、可为空的类、结构或可为空的结构。所以基本上什么都有。这是一个显示我的问题的简化示例:
#nullable enable
class Box<T> {
public T Value { get; }
public Box(T value) {
Value = value;
}
public static Box<T> CreateDefault()
=> new Box<T>(default(T));
}
由于使用了新的#nullable enable 功能,我收到以下警告:Program.cs(11,23): warning CS8653: A default expression introduces a null value when 'T' is a non-nullable reference type.
这个警告对我来说很有意义。然后我尝试通过在属性和构造函数参数中添加? 来修复它:
#nullable enable
class Box<T> {
public T? Value { get; }
public Box(T? value) {
Value = value;
}
public static Box<T> CreateDefault()
=> new Box<T>(default(T));
}
但现在我得到了两个错误:
Program.cs(4,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.
Program.cs(6,16): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.
但是,我不想添加约束。我不在乎 T 是类还是结构。
一个明显的解决方案是将违规成员包装在#nullable disable 指令下。但是,就像#pragma warning disable 一样,除非有必要,否则我想避免这样做。是否有其他方法可以在不禁用可空性检查或 CS8653 警告的情况下编译我的代码?
$ dotnet --info
.NET Core SDK (reflecting any global.json):
Version: 3.0.100-preview4-011223
Commit: 118dd862c8
【问题讨论】:
-
我没有更仔细地研究这个问题,但我假设
T?值类型和引用类型之间的差异根本不由编译器处理。为什么?我可以猜它只会增加大量的复杂性,但我也猜想您需要来自实际编译器人员的输入才能确定。值类型的T?由Nullable<T>处理,而C# 8 中引用类型的T?由具有属性的T处理。基本上,我认为这根本不被支持。 -
嗨@Andent,欢迎来到SO。您实际上是在打开一个设置,告诉编译器 not 允许将
null分配给T类型的变量(当T是引用类型时),然后使用@987654341 @ which 可以为引用类型返回null。这里没有什么神秘之处。你必须选择一条路径,比如 Neo... :-) -
您可能正在考虑同时制作
Box<T> where T : class和ValueBox<T> where T : struct。我认为目前没有办法通过T?和Nullable<T>统一泛型类型/方法。 -
从根本上说,可空类型和泛型不能很好地混合。根据我的经验,这是设计中最棘手的部分。
-
我认为您在这里有一些相互矛盾的目标。您想拥有
default框的概念,但对于引用类型,还有什么是合适的default?对于与使用可空引用类型直接冲突的引用类型,默认值为null。也许您需要将T限制为可以默认构造的类型 (new())。
标签: c# nullable c#-8.0 nullable-reference-types