Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用System.Text.Json处理可为null的引用类型? 我已经把我的项目升级到了磊科3,我正在重构一个项目来使用新的空引用类型特征,但是由于下面的问题,它很快就被卡住了。_Json_.net Core 3.0_Nullable Reference Types_System.text.json - Fatal编程技术网

如何使用System.Text.Json处理可为null的引用类型? 我已经把我的项目升级到了磊科3,我正在重构一个项目来使用新的空引用类型特征,但是由于下面的问题,它很快就被卡住了。

如何使用System.Text.Json处理可为null的引用类型? 我已经把我的项目升级到了磊科3,我正在重构一个项目来使用新的空引用类型特征,但是由于下面的问题,它很快就被卡住了。,json,.net-core-3.0,nullable-reference-types,system.text.json,Json,.net Core 3.0,Nullable Reference Types,System.text.json,假设我使用一个REST api,它返回以下JSON: { "Name": "Volvo 240", "Year": 1989 } 此api始终返回名称/年份,因此它们不可为空 我将使用这个简单的类进行反序列化: 公车 { 公共字符串名称{get;set;} 公共整数年{get;set;} } 我将使用新的System.Text.Json var car=JsonSerializer.Deserialize(json); 这一切都是可行的,但是当启用可为null的引用类型时,我在Ca

假设我使用一个REST api,它返回以下JSON:

{
  "Name": "Volvo 240",
  "Year": 1989
}
此api始终返回名称/年份,因此它们不可为空

我将使用这个简单的类进行反序列化:

公车
{
公共字符串名称{get;set;}
公共整数年{get;set;}
}
我将使用新的
System.Text.Json

var car=JsonSerializer.Deserialize(json);
这一切都是可行的,但是当启用可为null的引用类型时,我在
Car
类中得到一个警告,该警告声明为不可为null,但可以为null。我理解为什么会得到这个结果,因为可以在不初始化
Name
属性的情况下实例化这个对象

因此理想情况下,
Car
应如下所示:

公车
{
公共字符串名称{get;}
公共整数年{get;}
公共汽车(字符串名称,整数年)
{
名称=名称;
年=年;
}
}
但这不起作用,因为
System.Text.Json
序列化程序不支持带参数的构造函数

所以我的问题是:我如何声明
Car
,使
Name
不可为空,并使其在
System.Text.Json
中工作,而不得到“不可为空”的警告`


我不想使其可为null,因为在启用可为null的引用类型时,我必须对基本上所有内容进行null检查,并且因为我的示例中的REST API表示始终提供这些类型,所以它们不应为null。

更新

.NET5的
System.Text.Json
for.NET5现在支持参数化构造函数,因此这应该不再是一个问题

下面的旧答案

读了这本书之后,我发现了如何解决这个问题

因此,除非
System.Text.Json
无法使用构造函数中的参数实例化类,否则
Car
类必须如下所示:

公车
{
公共字符串名称{get;set;}=default!;
公共整数年{get;set;}
}
更新 如果您在
net5
,请使用@langen指出的参数化构造函数支持。下面的其他方法仍然有用

原创 略为另类的方法
System.Text.Json
使用私有无参数构造函数似乎没有问题。因此,您至少可以执行以下操作:

公车
{
公共字符串名称{get;set;}
公共整数年{get;set;}
//仅适用于System.Text.Json反序列化
#pragma warning disable CS8618//不可为空的字段未初始化。
私家车(){}
#pragma警告恢复CS8618
公共汽车(字符串名称,整数年)
{
名称=名称;
年=年;
}
}
好处是:

  • 来自您自己代码的对象的Init必须通过公共构造函数
  • 您不需要执行
    =null
S.T.Json和可空引用类型的剩余缺点:

  • Json仍然需要属性上的setter在反序列化期间实际设置值。我试过使用私有对象,但这是不可能的,所以我们仍然无法得到一个不变的对象

另一个选项,适用于那些希望处理有意义异常的缺失属性的人:

使用系统;
公车
{
私有字符串?名称;
私人国际年;
公共字符串名
{
get=>this.name??抛出新的invalidoOperationException($“{nameof(this.name)}未设置。”);
set=>this.name=value;
}
公共国际年
{
get=>this.year??抛出新的InvalidOperationException($“{nameof(this.year)}未设置。”);
set=>this.year=值;
}
}

就个人而言,我宁愿使用
=”,否则您基本上是在说(在我看来)“这个属性永远不会为null(只是开玩笑)”。或者使用JSON.NET。System.Text.Json还不是完全的替代品。至于
=默认值
。。。还没有。当我在2019年10月读到这篇文章时,我认为
您正在将其设置为null。也许明年吧。这与微软推荐的实体对象类似。EF团队实际上建议使用
null
作为一种说法,“我知道这永远不会是
null
”,尽管我喜欢这种可空性的潜力,但这确实让人感觉有点不舒服。…。@LasseV.Karlsen注意,在asp.net的上下文中,添加
=null
实际上是在请求对象上修饰所需属性的正确方法。它是
[Required]
属性的后续项。添加
=null
将简单地告诉编译器您知道自己在做什么,它将不允许将字符串反序列化为null。由于字符串不可为空,asp.net将拒绝未为不可为空/必需的引用类型指定值的任何请求。请注意,执行
#nullable disable
实际上会禁用空限制——所以不要这样做@MattJacobi
System.Text.Json
将愉快地将
null
反序列化为不可为null的字符串属性;至少在默认情况下,不管反序列化类(我刚刚尝试过)的状态如何,是否有一些选项触发这种更严格的“我真的是指可空性”模式?