我想创建一个具有类型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
答案 0 :(得分:4)
如关于该问题的评论中所述,您可能需要考虑具有默认值的Box<string>
在可为空的上下文中是否有效,并可能相应地调整您的API表面。为了使包含默认值的实例有效,也许类型必须为Box<string?>
。但是,在某些情况下,您将需要指定属性,方法返回值或参数等仍然为空,即使它们具有不可为空的引用类型。如果您属于该类别,则可能需要使用与可空性相关的属性。
.NET Core 3中引入了MaybeNull和AllowNull属性来处理这种情况。
这些属性的某些特定行为仍在发展,但基本思想是:
[MaybeNull]
表示某事物(读取字段或属性,方法返回等)的输出可能是null
。[AllowNull]
表示对某物(写字段或属性,方法参数等)的输入可以是null
。#nullable enable
using System.Diagnostics.CodeAnalysis;
class Box<T>
{
[MaybeNull]
public T Value { get; }
public Box([AllowNull] T value) // 1
{
Value = value;
}
public static Box<T> CreateDefault()
{
return new Box<T>(default(T)!); // 2
}
public static void UseStringDefault()
{
var box = Box<string>.CreateDefault();
_ = box.Value.Length; // 3
}
public static void UseIntDefault()
{
var box = Box<int>.CreateDefault();
_ = box.Value.ToString(); // 4
}
}
注意:
[MaybeNull]
中删除了Value
属性,则不会收到有关为其分配[AllowNull] T value
参数的警告。实际上,[AllowNull]
只是阻止在呼叫站点发出可能为空的参数警告。default(T)
,但是也可能发生在调用以[MaybeNull]
注释其返回值的泛型方法时。目前,我们通过使用default(T)!
取消警告来解决该问题。box.Value
注释,我们在取消引用[MaybeNull]
时会给出可空性警告。box.Value
是不可为空的值类型。有关更多信息,请参见https://devblogs.microsoft.com/dotnet/try-out-nullable-reference-types,尤其是“ the issue with T?”部分。
答案 1 :(得分:0)
杰夫·梅卡多(Jeff Mercado)在评论中提出了一个好观点:
我认为您的目标有些矛盾。您想拥有默认框的概念,但对于引用类型,还有什么合适的默认值?对于与使用可为空的引用类型直接冲突的引用类型,默认值为null。也许您需要将T约束为可以默认构造的类型(new())。
例如,then()
的{{1}}将是default(T)
,因为在运行时T = string
和null
之间没有区别。这是语言功能的当前限制。
我通过为每种情况创建单独的string
方法来解决这种局限性:
string?
此似乎类型对我来说很安全,但要花更麻烦的呼叫站点(CreateDefault
而不是#nullable enable
class Box<T> {
public T Value { get; }
public Box(T value) {
Value = value;
}
}
static class CreateDefaultBox
{
public static Box<T> ValueTypeNotNull<T>() where T : struct
=> new Box<T>(default);
public static Box<T?> ValueTypeNullable<T>() where T : struct
=> new Box<T?>(null);
public static Box<T> ReferenceTypeNotNull<T>() where T : class, new()
=> new Box<T>(new T());
public static Box<T?> ReferenceTypeNullable<T>() where T : class
=> new Box<T?>(null);
}
)。在我发布的示例类中,我将完全删除方法并直接使用CreateDefaultBox.ReferenceTypeNullable<object>()
构造函数。哦,很好。
答案 2 :(得分:-5)
const regex = /^(.+ \?)\n((?:\n(?!.* \?$).*)*)/gm;
const str = `Combien ?
Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum.
test
Combien 2 ?
Lorem ipsum.Lorem ipsum.Lorem ipsum.Lorem ipsum. Lorem ipsum.Lorem ipsum.Lorem ipsum. Lorem ipsum.Lorem ipsum.Lorem ipsum.Lorem ipsum.Lorem ipsum.`;
let m;
while ((m = regex.exec(str)) !== null) {
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
console.log("Question: " + m[1]);
console.log("Answer: " + m[2]);
}