我有以下类(class):
class GenericClass<T>
{
public T? A { get; init; }
public T B { get; init; }
public GenericClass(T? a, T b)
{
A = a;
B = b;
}
}
我想将它用于任何类型的 T
,无论 struct
, class
, enum
。我只是想确保该属性 A
当属性 B
时可以始终为 null的可空性与 T
相同的。但这似乎不起作用。
如果我写
static void MyTestMethod()
{
var vStruct = new GenericClass<bool>(null, true);
var vNullableStruct = new GenericClass<bool?>(null, true);
var vClass = new GenericClass<string>(null, "hello");
var vNullableClass = new GenericClass<string?>(null, "hello");
var vEnum = new GenericClass<Color>(null, Color.red);
var vNullableEnum = new GenericClass<Color?>(null, Color.red);
}
哪里Color
定义为enum Color { red, green, blue }
,
我收到 vStruct
的编译器错误 CS1503和vEnum
:
Argument '1': cannot convert from
<NULL>
tobool
/Color
在这两种情况下,鼠标悬停为 new GenericClass<...>
尽管我明确定义了A
,但将两个参数显示为不可空可以为空。 为什么?
我可以添加类型约束:class GenericClass<T> where T : struct
,这将使之前错误的两行( vStruct
和 vEnum
)没有错误,但会将所有其他行标记为错误。这次出现编译器错误 CS0453:
The type
bool?
/string
/string?
/Color
must be a non-nullable value type in order to use it as parameterT
in the generic type or methodGenericClass<T>
.
这完全有道理;他们不是struct
.
但是我该如何制作我的 GenericClass<T>
适用于类和结构/枚举?
最佳答案
下面sjb-sjb的评论this answer提供了我的“为什么”的答案:
As it is, in C#9, with T unconstrained (or even constrained to notnull), the syntax "T?" means "the defaultable type corresponding to T" instead of "the nullable type corresponding to T" as it does everywhere else in the language. However if you constrain T to class or struct then "T?" starts meaning "the nullable type corresponding to T" again.
感谢 JonasH 的评论,我想出了一个解决方案/解决方法。我创建了一个自定义 Nullable<T>
具有从 T?
隐式转换的类型至Nullable<T>
这样我就可以在 GenericClass<...>
的构造中使用几乎相同的语法正如我在问题中使用的:
struct Nullable<T>
{
public static Nullable<T> Null => new Nullable<T>(false, default(T)!);
public bool HasValue { get; init; }
private T? _value;
public T Value
{
get => HasValue ? _value
: throw new System.InvalidOperationException("no value present!");
init => _value = value;
}
private Nullable(bool hasValue, T value)
{
HasValue = hasValue;
_value = value;
}
public static implicit operator Nullable<T>(T? n)
=> n == null ? Null : new Nullable<T>(true, n);
}
两条有问题的线路
var vStruct = new GenericClass<bool>(null, true);
var vEnum = new GenericClass<Color>(null, Color.red);
仍然抛出CS1503,但我可以将它们更改为
var vStruct = new GenericClass<bool>(Nullable<bool>.Null, true);
var vEnum = new GenericClass<Color>(Nullable<Color>.Null, Color.red);
并且它有效。我可以对其他线路做同样的事情,但我不需要这样做;那里使用了隐式转换。
关于c# - 使用泛型类型的可空属性的泛型类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72627384/