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

Why does Visual Studio generate warning CS620 when passing KeyValuePair enumeration to FormUrlEncodedContent constructor?

考虑以下代码:

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);
        }
    }
}

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

Warning CS8620 Argument of type 'Dictionary<string, string>' cannot be used for parameter 'nameValueCollection' of type 'IEnumerable<KeyValuePair<string?, string?>>' in 'FormUrlEncodedContent.FormUrlEncodedContent(IEnumerable<KeyValuePair<string?, string?>> nameValueCollection)' due to differences in the nullability of reference types.

documentation for FormUrlEncodedContent 表示构造函数应该接受 IEnumerable<KeyValuePair<string,string>>?。我的 map 变量是一个 Dictionary<string,string>,大概会实现接口 IEnumerable<KeyValuePair<string,string>>,所以我希望这里没有问题。 为什么会出现警告?

我正在使用 Visual Studio 16.8.0 目标 NETCore5。

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

  1. 为什么文档有误?而且,
  2. 为什么发出警告。

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

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

static void Main(string[] args)
{
    var map = new Dictionary<string, string>()
    {
        ["hello"] = "world"
    };

    M1(map);
}

static void M1(IEnumerable<KeyValuePair<string?, string?>>? nameValueCollection) { }

可以从您 copy/pasted 的警告中推断出您的问题 actual .NET 5 版本的声明 FormUrlEncodedContent class 构造函数必须是,所以我只是写了一个不需要安装 .NET 5 的例子。

事实上,如果我们查看 the source code,我们可以看到该构造函数的实际声明:

public FormUrlEncodedContent(IEnumerable<KeyValuePair<string?, string?>> nameValueCollection)

这告诉我文档不准确,如果不是完全错误的话。我没有关注支持可空引用类型的框架的变化,所以我不确定文档是否应该为这种情况显示可空类型参数。在我看来应该,但显然不是。至少,令我惊讶的是文档将 nameValueCollection 参数本身显示为可为空(实际上它不是),不要介意它将 KeyValuePair<TKey, TValue> 类型参数显示为 non-nullable ,而实际上它们可以为空。

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

为什么这会产生警告?好吧……虽然我们知道在这种情况下没有代码会写入可枚举值中的可为空值,但没有 compile-time 保证 。由于您的对象正在返回值是 non-nullable 引用的对象,并且您将其传递给声明为接受可为 null 的值的方法,这意味着理论上该方法可以 modify 通过将这些可为空的值设置为 null,这违反了您自己的代码假设这些值为 non-nullable.