簡體   English   中英

C# 8 中可空類型和 Generics 的問題

[英]A problem with Nullable types and Generics in C# 8

添加<Nullable>enable</Nullable>#nullable enable后,我的通用方法遇到了以下問題:

這不起作用:

public T? GetDefault<T>()
{
    return default;
}

在此處輸入圖像描述

這適用於警告:

public T GetDefault<T>()
{
   return default;
}

在此處輸入圖像描述

這可以單獨使用,但不能一起使用。

public T? GetDefault<T>() where T : class
{
    return default;
}

public T? GetDefault<T>() where T : struct
{
    return default;
}

在此處輸入圖像描述

從邏輯上講,第一種方法應該有效。
在不創建多種方法和抑制警告的情況下,擺脫這種情況的正確方法(在任何框架中)是什么?
[MaybeNull] 屬性僅適用於 .Net Core 3.0+。

另外,我在這里問了這個問題

T? 只能在已知類型參數是引用類型或值類型時使用。 否則,我們不知道是將其視為System.Nullable<T>還是可空引用類型T

相反,您可以使用[MaybeNull]屬性在 C# 8 中表達此場景。

#nullable enable
using System.Diagnostics.CodeAnalysis;

public class C
{
    [return: MaybeNull]
    public T GetDefault<T>()
    {
        return default!; // ! just removes warning
    }
}

此屬性僅包含在 .NET Core 3.0+ 中,但可以在項目內部聲明和使用該屬性(雖然這不受官方支持,但沒有理由假設該行為會破壞線)。 為此,您只需在代碼中添加一個命名空間+類聲明,如下所示:

namespace System.Diagnostics.CodeAnalysis
{
    /// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
    internal sealed class MaybeNullAttribute : Attribute { }
}

問題的解釋

出現第一個代碼示例中的問題是因為編譯器以不同的方式處理可空值類型和可空引用類型:

  • 可空值類型T? 由類型Nullable<T>表示。
  • 可空引用類型T? 是相同的類型T但具有編譯器生成的屬性對其進行注釋。

編譯器無法同時生成涵蓋這兩種情況的代碼,因此會發生編譯錯誤。 這個錯誤迫使我們指定classstruct約束。 C# specification中也說明了這種行為:

對於類型參數T , T? 僅當T已知為值類型或已知為引用類型時才允許。

可以在這篇文章中找到對這個問題的一個很好的解釋: 試用 Nullable Reference Types 滾動到“ T? ”段落。


解決問題的解決方法

如果您不想創建兩個具有不同名稱的方法並禁止顯示警告,則可以使用下一個解決方法:

// An overload that will be used by reference types.
public T? GetDefault<T>(T? t = default) where T : class
{
    return default;
}

// An overload that will be used by value types.
public T? GetDefault<T>(T? t = default) where T : struct
{
    return default;
}

在這里,我們在GetDefault方法中添加了一個參數t ,以使編譯器能夠區分這兩種方法。 現在我們可以使用GetDefault方法,編譯器將定義要使用的重載。 這種方法的缺點是GetDefault方法有不可用的參數t

似乎這個問題的最佳解決方案只會在C# 9 as T??

鏈接:
1. https://github.com/dotnet/cshaplang/issues/3471#issuecomment-631722668
2. https://github.com/dotnet/cshaplang/issues/3297

目前,Rikki Gibson 提供了一個可行的解決方案。 它意味着額外的代碼,但它可以正常工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM