繁体   English   中英

泛型 class 使用泛型类型的可空属性

[英]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 ,无论是structclass 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 }

我收到vStructvEnum

参数“1”:无法从<NULL>转换为bool / Color

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

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM