簡體   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