[英]generic class using nullable property of generic type
我有以下 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
始终可以为 null,而属性B
的可空性与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
和vEnum
:
参数“1”:无法从
<NULL>
转换为bool
/Color
在这两种情况下, new GenericClass<...>
的鼠标悬停都显示 arguments 为不可空,尽管我明确将A
定义为可空。 为什么?
我可以添加一个类型约束: class GenericClass<T> where T: struct
,这将使之前出错的两行( vStruct
和vEnum
)没有错误,但会将所有其他行标记为错误。 这次出现编译器错误 CS0453:
bool?
/string
/string?
/Color
必须是不可为 null 的值类型,才能将其用作泛型类型或方法GenericClass<T>
中的参数T
这是完全有道理的; 他们不是struct
。
但是如何让我的GenericClass<T>
同时适用于类和结构/枚举?
sjb-sjb 在此答案下方的评论提供了我的“为什么”的答案:
实际上,在 C#9 中,T 不受约束(甚至约束为 notnull),语法“T?” 表示“对应于 T 的可默认类型”,而不是“对应于 T 的可空类型”,就像它在语言中的其他地方一样。 但是,如果您将 T 限制为 class 或结构,则“T?” 再次开始表示“对应于 T 的可空类型”。
感谢 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);
它有效。 我可以对其他行做同样的事情,但我不需要; 隐式转换在那里使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.