在 C# 6 索引初始值设定项中使用 C# 8 null-forgiving 运算符

Use of C# 8 null-forgiving operator within C# 6 index initializers

当使用索引初始值设定项来填充字典而不在此之前重新创建它时,是否可以选择在某处指定 null-forgiving 运算符?

示例:

public class Program
{
    public IDictionary<string, string>? NullableDictionary { get; set; }
       = new Dictionary<string, string>();

    public static void Main(string[] args)
    {
        new Program
        {
            NullableDictionary =
            {
                ["key"] = "value"
            }
        };
    }
}

我知道这个用例(在索引初始化 { [...] = ... } 之前没有重新创建 new Dictionary<string, string>)可能不是很常见。 但我仍然想知道是否有解决方案来防止针对上述情况出现此编译器警告:

[CS8602] Dereference of a possibly null reference.

我可以想象像这样使用 null-forgiving 运算符:

new Program
{
    NullableDictionary! =
    {
        ["key"] = "value"
    }
};

I am still wondering whether there is a solution to prevent this compiler warning

我假设你的意思是,除了明显的 #pragma 方法:

#pragma warning disable 8602
    new Program
    {
        NullableDictionary = { ["key"] = "value" }
    };
#pragma warning restore

这显然有效。或者,当然,上面的 "nullable reference types" 特定版本:

#nullable disable
    new Program
    {
        NullableDictionary = { ["key"] = "value" }
    };
#nullable restore

这两个都暂时明确地禁用了相关警告。 null-forgiving 运算符本质上就是这样做的,当然除了它所应用的特定表达式之外。

无论好坏,我认为没有办法完全按照您的意愿进行。通常,仅在实际变量声明中才允许使用集合初始化程序语法。基于场景的相似性,在对象初始化器语法上下文中使用它是语言允许的一种特殊情况,即使生成的代码与实际的变量初始化有很大不同(特别是,你在实际上是在初始化集合的同时初始化变量的值。

因此,当编译器处理您的集合初始化器语法时,编译器所要做的就是生成一堆对 Add() 方法的调用,并且这些调用是根据您之前的声明,正在设置一个可能为空的参考值。

综上所述,我发现您尝试在那里使用 null-forgiving 运算符非常明智。如果编译器通过在它生成的每个 Add() 调用中包含该运算符来解释该运算符在该上下文中的使用,那就太好了。

您甚至可以针对该语言提出 Git 问题,并要求将其添加为一项功能。我认为这不会是一个重大变化,因为该语法目前完全是非法的,并且在您不使用该语法时允许它不会改变编译器的行为。