将 KeyValuePair 枚举传递给 FormUrlEncodedContent 构造函数时,为什么 Visual Studio 会生成警告 CS620?

Fes*_*ale 5 c# syntax compiler-warnings .net-5

考虑以下代码:

using System;
using System.Collections.Generic;
using System.Net.Http;

namespace dla.test2{
    internal class Test{
        public static void Main(){
            var map=new Dictionary<string,string>(){
                ["hello"]="world"
            };
            using var foo=new FormUrlEncodedContent(map);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

调用 的构造函数会FormUrlEncodedContent在构建时产生以下编译器警告:

警告 CS8620类型为“Dictionary<string, string>”的参数不能用于“FormUrlEncodedContent.FormUrlEncodedContent(IEnumerable<KeyValuePair<string?, string”中的“IEnumerable<KeyValuePair<string?, string?>>”类型的参数“nameValueCollection” ?>> nameValueCollection)' 由于引用类型可空性的差异。

FormUrlEncodedContent 的文档表明构造函数应该接受IEnumerable<KeyValuePair<string,string>>?. 我的map变量是 a Dictionary<string,string>,大概会实现该接口IEnumerable<KeyValuePair<string,string>>,所以我希望这里不会有问题。那么为什么会出现警告呢?

我正在使用针对 NETCore5 的 Visual Studio 16.8.0。

Pet*_*iho 3

我觉得这里实际上有几个问题:

\n
    \n
  1. 为什么文档是错误的?和,
  2. \n
  3. 为什么发出警告。
  4. \n
\n

后者更容易回答。前者,没有那么多(你必须问微软)。

\n

我还没有安装 .NET 5。但我可以使用以下代码在 .NET Core 3.1 中重现完全相同的警告:

\n
static void Main(string[] args)\n{\n    var map = new Dictionary<string, string>()\n    {\n        ["hello"] = "world"\n    };\n\n    M1(map);\n}\n\nstatic void M1(IEnumerable<KeyValuePair<string?, string?>>? nameValueCollection) { }\n
Run Code Online (Sandbox Code Playgroud)\n

可以从您复制/粘贴到问题中的警告推断出.NET 5 版本的类构造函数的实际FormUrlEncodedContent声明必须是什么,因此我只是编写了一个不需要 .NET 5 的示例被安装。

\n

事实上,如果我们查看源代码,我们可以看到该构造函数的实际声明:

\n
public FormUrlEncodedContent(IEnumerable<KeyValuePair<string?, string?>> nameValueCollection)\n
Run Code Online (Sandbox Code Playgroud)\n

这告诉我,该文档即使不是完全错误,也是不准确的。我没有关注支持可为空引用类型的框架的更改,因此我不确定文档是否应该显示这种情况的可为空类型参数。在我看来应该如此,但显然不是。至少,令我惊讶的是,文档将参数nameValueCollection本身显示为可为空(事实上并非如此),更不用说它将类型KeyValuePair<TKey, TValue>参数显示为不可为空,而实际上它们是可以为空。

\n

但无论如何,通过了解.NET 5 中的实际方法签名是什么,我们可以说警告的存在仅仅是因为您的调用确实涉及传递与类型参数的可空性不一致的类型。

\n

为什么这会产生警告?嗯\xe2\x80\xa6 虽然我们知道在这种情况下没有代码会写入可枚举值中的可为空值,但对此没有编译时保证。由于您的对象返回的对象的值是不可为空的引用,并且您将其传递给声明为接受可为空的值的方法,这意味着理论上,该方法可以通过将这些可为空的值设置为 来修改null它们,违反了您自己的代码关于值不可为空的假设。

\n