C#8-CS8605枚举中的“拆箱可能为空值”

问题描述

我在.csproj中有一个带有<nullable>enable</nullable>的项目 并且我正在经历一些奇怪的警告行为。

我有一个遍历枚举的foreach语句,并且枚举中的foreach项运行一些代码。 但是,当我尝试执行此操作时,VS2019会标记CS8605“取消装箱可能为空值”警告。

enter image description here

此处显示完整代码错误显示t的减速度。

public static class Textures
{
    private static readonly Dictionary<TextureSet,Texture2D> textureDict = new Dictionary<TextureSet,Texture2D>();

    internal static void LoadContent(ContentManager contentManager)
    {
        foreach(TextureSet t in Enum.GetValues(typeof(TextureSet)))
        {
            textureDict.Add(t,contentManager.Load<Texture2D>(@"textures/" + t.ToString()));
        }
    }

    public static Texture2D Map(TextureSet texture) => textureDict[texture];
}

我正在努力理解为什么t可能为null的原因,因为枚举不可为空。 我想知道,由于Enum.GetValues返回的类型为Array,这里是否存在隐式强制转换,这是此问题的根源。 我目前的解决方案只是抑制警告。但是我想了解这里发生了什么。也许有更好的方法来遍历枚举。

我正在使用.net Core 3.1和Visual Studio Community 2019 16.7.2

解决方法

我是否在流连忘返,因为如果有Enum.GetValues返回类型为Array 是在这里进行一些隐式转换,这是此操作的根源 问题。

是的,由foreach循环进行了隐式转换。这是问题的根源。

您已经注意到Enum.GetValues返回类型为Array的对象。在启用nullable context的情况下,Array的项目为可空类型object?。在foreach循环中遍历Array时,每个Array项目都将转换为迭代变量的类型。在您的情况下,类型Array的每个object?项目都强制转换为类型TextureSet。此强制转换会产生警告Unboxing possibly null value

如果您在sharplab.io中尝试代码,则会看到内部的C#编译器将考虑到的foreach循环转换为while循环,从而清楚地显示了问题(为简化起见,我省略了一些代码块):

IEnumerator enumerator = Enum.GetValues(typeof(TextureSet)).GetEnumerator();
while (enumerator.MoveNext())
{
    // Type of the enumerator.Current is object?,so the next line
    // casts object? to TextureSet. Such cast produces warning
    // CS8605 "Unboxing possibly null value".
    TextureSet t = (TextureSet) enumerator.Current;
}

我目前的解决方案只是抑制警告。 ...也许有更好的方法来遍历枚举。

您还可以使用下一个approach来修复警告:

foreach (TextureSet t in (TextureSet[]) Enum.GetValues(typeof(TextureSet)))
{
}