C# Nullable:如何从 Dictionary<string,string> 构建 FormUrlEncodedContent

C# Nullable: How to build a FormUrlEncodedContent from Dictionary<string,string>

我有 Dictionary<string,string> 个参数,想创建一个 FormUrlEncodedContent。请参阅以下示例代码:

var message = new Dictionary<string,string> {{"example", "example"}};
var content = new FormUrlEncodedContent(message);

这段代码在禁用 nullable 的情况下工作正常,但启用它会导致警告(并且由于我们启用了 WarningsAsErrors,因此构建失败)。

Argument of type 'System.Collections.Generic.Dictionary<string,string>' cannot
be used for parameter 'nameValueCollection' of type 
'System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string?,string?>>'
in 'System.Net.Http.FormUrlEncodedContent.FormUrlEncodedContent'
due to differences in the nullability of reference types.

我已经通过 message.Select(kvp => new KeyValuePair<string?, string?>(kvp.Key, kvp.Value)) 解决了这个问题,但这非常冗长、粗暴,而且可能更慢。

有什么建议吗?我是不是错过了一个明显的投射方式,或者 FormUrlEncodedContent class 接受 KeyValuePair<string?, string?> 是错误的?

我似乎找到了解决方法 as:

var content = new FormUrlEncodedContent(
                message.AsEnumerable() as IEnumerable<KeyValuePair<string?,string?>>);

! (null-forgiving) operator 成功了:

var message = new Dictionary<string, string> { { "example", "example" } };
var content = new FormUrlEncodedContent(message!);

我所知道的当前 C# 的最佳解决方案是使用 !SharpLab

#nullable enable

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

var message = new Dictionary<string,string> {{"example", "example"}};
var content = new FormUrlEncodedContent(message!);

这里的问题是结构和 class 类型参数是 invariant。因此,例如,我们不允许将 KeyValuePair<string, string> 隐式转换为 KeyValuePair<string?, string?>,即使这样做并没有真正的安全问题。

Task<T> 针对类似问题的解决方案已 proposed。也许该语言应该引入一种在 TaskKeyValuePair 场景下都有效的解决方案,也许可以扩展到其他场景。

编辑:此问题还揭示了编译器中的一个错误,其中某些不允许的嵌套可空性转换不会产生警告。为了避免依赖这个错误,我更改了推荐的解决方案。 https://github.com/dotnet/roslyn/issues/53189