c# - 使用泛型类型的可空属性的泛型类

标签 c# generics nullable nullable-reference-types

我有以下类(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> to bool/Color

在这两种情况下,鼠标悬停为 new GenericClass<...>尽管我明确定义了A,但将两个参数显示为不可空可以为空。 为什么?

我可以添加类型约束:class GenericClass<T> where T : struct ,这将使之前错误的两行( vStructvEnum )没有错误,但会将所有其他行标记为错误。这次出现编译器错误 CS0453:

The type bool?/string/string?/Color must be a non-nullable value type in order to use it as parameter T in the generic type or method GenericClass<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/

相关文章:

c# - 用于 Linux 的 WinForms 设计器

java - 在 Java 中扩展通用接口(interface)并使其更加严格

java - 验证输入字段时忽略空值

c# - 检查 JValue 是否为空

c# - 从图像设置自适应平铺背景

c# - 在 C# 中 try catch 的不同方法

swift 2 : How to refer to a type of an element in default implementation of a function in a protocol

c# - 显式接口(interface)和通用/动态类型转换

c# - WPF 文本框接受 INT 但不接受 NULLABLE INT?

c# - 将光标位置设置为系列中的下一个文本框