Mar*_*eIV 6 c# generics nullable nullable-reference-types
在 C# 中使用新的可为空引用类型。很高兴看到他们从 Swift 中挖走了这个!这是一个非常棒的功能!但是...因为它本质上是“固定在”语言上的,所以我正在努力创建一个泛型,它可以采用任何可空类型,无论是值还是引用,这在 Swift 中都是微不足道的。
考虑这个类:
public abstract class LabeledValue<TValue> {
public string? label { get; set; }
public TValue? value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这是我想要实现的目标,以Int一个名为“Foo”的类为例:
public class LabeledInt : LabeledValue<Int>{}
var myLabeledIntA = new LabeledInt(){
label = "Forty Four",
value = 44
}
var myLabeledIntB = new LabeledInt(){
label = "Not Set",
value = null
}
public class LabeledFoo : LabeledValue<Foo>{}
var myLabeledFooA = new LabeledFoo(){
label = "Set",
value = new Foo()
}
var myLabeledFooB = new LabeledFoo(){
label = "Not Set",
value = null
}
Run Code Online (Sandbox Code Playgroud)
这抱怨我必须将 TValue 定义为可空。但是,我找不到可以解决可为空值类型(即 Int?)和可为空引用类型(即 Foo?)的约束。如何编写这样的约束?
这些都行不通...
public abstract class LabeledValue<TValue>
where TValue : Nullable {
public string? label { get; set; }
public TValue? value { get; set; }
}
public abstract class LabeledValue<TValue>
where TValue : struct {
public string? label { get; set; }
public TValue? value { get; set; }
}
public abstract class LabeledValue<TValue> {
public string? label { get; set; }
public Nullable<TValue> value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
请注意,我也尝试过这种想法,认为可空性可以作为实际类型参数传入,但随后它抱怨未设置“值”。
public abstract class LabeledValue<TValue> {
public string? label { get; set; }
public TValue value { get; set; }
}
public class LabeledInt : LabeledValue<Int?>{}
Run Code Online (Sandbox Code Playgroud)
好的,找到了。您必须使用两个新的显式属性AllowNull和MaybeNull。
这是修改后的代码...
public abstract class LabeledValue<TValue> {
public string? label { get; set; }
[AllowNull, MaybeNull]
public TValue value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
通过这一更改,我现在可以执行以下所有操作......
public class LabeledInt : LabeledValue<int>{}
public class LabeledNInt : LabeledValue<int?>{}
public class LabeledFoo : LabeledValue<Foo>{}
public class LabeledNFoo : LabeledValue<Foo?>{}
Run Code Online (Sandbox Code Playgroud)
并像这样使用它们......
var a = new LabeledInt();
a.Value = 4;
a.value = null // This won't compile
var b = new LabeledNInt();
b.Value = 4;
b.Value = null; // This compiles just fine
var c = new LabeledFoo();
c.Value = new Foo();
c.Value = null; // This won't compile
var d = new LabeledNFoo();
d.Value = new Foo();
d.Value = null; // This compiles just fine
Run Code Online (Sandbox Code Playgroud)
注意:仍然有未初始化的警告
Value,但这只是警告,不是错误。您必须确保Value在访问它之前显式设置非空类型。有点违背了使用可空/不可空类型的目的,但这更像是一种黑客行为,而不是真正的解决方案,这实际上是不可能的,因为可空值类型实际上是具体的,而可空引用类型Nullable<T>是常规引用类型,只是装饰有属性让编译器知道不接受空值。