做电商网站的感想网站建设视频教程百度云
做电商网站的感想,网站建设视频教程百度云,建企业网站一般多少钱,qq电脑版网页登录9月14日#xff0c;.NET5发布了(Release Candidate)RC1版本#xff0c;RC的意思是指我们可以进行使用#xff0c;并且RC版本得到了支持#xff0c;该版本是接近.NET5的版本#xff0c;也是11月正式版本之前两个RC版本中的其中一个。目前#xff0c;开发团队正在寻找在.NE… 9月14日.NET5发布了(Release Candidate)RC1版本RC的意思是指我们可以进行使用并且RC版本得到了支持该版本是接近.NET5的版本也是11月正式版本之前两个RC版本中的其中一个。目前开发团队正在寻找在.NET5发布之前剩余的bug当然他们也希望我们的反馈以帮助他们顺利的完成.NET5的开发计划。开发团队在今天还发布了ASP.NET Core和EF Core的RC1版本。现在我们可以进行下载用于Windows、macOS和Linux的.NET5Installers and binariesContainer imagesSnap installerRelease notesKnown issuesGitHub issue tracker如果要使用.NET5我们需要使用最新的Visual Studio预览版(包括Visual Studio for Mac)在.NET5中有许多的改进特别是对单文件可执行应用程序、更小的容器映像、更强大的JsonSerializer api、BCL nullable reference type annotated、新target framework names以及对Windows ARM64的支持。在.NET库中GC和JIT的性能都得到了极大的提升ARM64是性能优化的重点它为我们带来了更好的吞吐量和更小的二进制文件。.NET5.0包含了新的语言版本C#9和F#5.0。下面还有他们最近发布的一些有关于.NET5.0新功能的文章大家可以阅读一下F# 5 update for AugustARM64 Performance in .NET 5Improvements in native code interop in .NET 5.0Introducing the Half type!App Trimming in .NET 5Customizing Trimming in .NET 5Automatically find latent bugs in your code with .NET 5其实就像在.NET5 Preview8中一样在本章还是像上一章一样选择了一些特性来进行深入的研究介绍在本章中将深入的讨论C#9中新特性records和System.Text.Json.JsonSerializer它们是独立的特性但也是很好的一个组合特别是在我们花费一些时间去为反序列化的JSON对象设计POCO类型时。C# 9 — RecordsRecords可能是c#9中最重要的一个新特性它们提供了一个广泛的特性集(对于一种语言类型)其中一些需要RC1或更高的版本(如record.ToString())。将records看作不可变类是最简单的方式在特性方面它们很接近元组(Tuple),可以将他们视为具有属性和不可变性的自定义元组。在今天使用元组的许多情况下records可以更好的提供这些元组。如果你正在使用C#你会得到最好的体验如果你使用命名类型相对于像元组这样的特性。静态类型是该语言主要的设计要点records使小型类型更容易使用并在整个应用程序中利用类型安全。Records are immutable data typesRecords使我们能够创建不可变的数据类型这对于定义存储少量数据的类型非常有用。下面是一个records的示例它存储登录用户信息.public record LoginResource(string Username, string Password, bool RememberMe);
在语义中与下面的几乎完全相同当然下面将会很快的去介绍这些的差异性。public class LoginResource
{public LoginResource(string username, string password, bool rememberMe){Username username;Password password;RememberMe rememberMe;}public string Username { get; init; }public string Password { get; init; }public bool RememberMe { get; init; }
}
init是一个新的关键字它是set的代替set允许我们在任何时候分配一个属性init只允许在对象构建期间进行属性的赋值操作它是records的不变性所依赖的基础任何类型都可以使用init。正如我们在前面的定义中所看到的那样它不是特定于records的。private set看起来类似于init;private set防止其他代码类型以外的代码改变数据当类型在构建之后意外的改变属性时init将在编译器生成时返回错误。private set并非旨在为不可变数据建模因此当类型在构造后使属性值发生冲突时private set不会产生任何编辑器错误或者警告。Records are specialized classes正如上面提到的LoginResource的records的变量和类变量几乎是相同的类定义是记录的一个语义相同的子集records 提供了更多的、专门的行为。下面是比较一个record和一个使用init而不是set作为属性类之间的比较。有什么相同ConstructionImmutabilityCopy semantics (records are classes under the hood)有什么不同records相等性是基于内容的。基于对象标识的类相等性records提供了一个GetHashCode()实现它基于record内容records提供一个IEquatable实现。它使用唯一的GetHashCode()行为作为机制为record提供基于内容的相等语义。覆盖Record ToString()以打印record内容。record和类(使用init)之间的差异可以在LoginResource作为记录和LoginResource作为类的反汇编中看到。下面代码片段中将演示这些差异using System;
using System.Linq;
using static System.Console;var user Lion-O;
var password jaga;
var rememberMe true;
LoginResourceRecord lrr1 new(user, password, rememberMe);
var lrr2 new LoginResourceRecord(user, password, rememberMe);
var lrc1 new LoginResourceClass(user, password, rememberMe);
var lrc2 new LoginResourceClass(user, password, rememberMe);WriteLine($Test record equality -- lrr1 lrr2 : {lrr1 lrr2});
WriteLine($Test class equality -- lrc1 lrc2 : {lrc1 lrc2});
WriteLine($Print lrr1 hash code -- lrr1.GetHashCode(): {lrr1.GetHashCode()});
WriteLine($Print lrr2 hash code -- lrr2.GetHashCode(): {lrr2.GetHashCode()});
WriteLine($Print lrc1 hash code -- lrc1.GetHashCode(): {lrc1.GetHashCode()});
WriteLine($Print lrc2 hash code -- lrc2.GetHashCode(): {lrc2.GetHashCode()});
WriteLine(${nameof(LoginResourceRecord)} implements IEquatableT: {lrr1 is IEquatableLoginResourceRecord} );
WriteLine(${nameof(LoginResourceClass)} implements IEquatableT: {lrr1 is IEquatableLoginResourceClass});
WriteLine($Print {nameof(LoginResourceRecord)}.ToString -- lrr1.ToString(): {lrr1.ToString()});
WriteLine($Print {nameof(LoginResourceClass)}.ToString -- lrc1.ToString(): {lrc1.ToString()});public record LoginResourceRecord(string Username, string Password, bool RememberMe);public class LoginResourceClass
{public LoginResourceClass(string username, string password, bool rememberMe){Username username;Password password;RememberMe rememberMe;}public string Username { get; init; }public string Password { get; init; }public bool RememberMe { get; init; }
}注意我们会注意到LoginResource类型以Record和Class结束。该模式并不是新的命名模式的规范这样命名只是为了我们在代码片段中有相同类型的record和类变量。请不要这样命名我们的类型。如下是上面代码的输出内容richthundera records % dotnet run
Test record equality -- lrr1 lrr2 : True
Test class equality -- lrc1 lrc2 : False
Print lrr1 hash code -- lrr1.GetHashCode(): -542976961
Print lrr2 hash code -- lrr2.GetHashCode(): -542976961
Print lrc1 hash code -- lrc1.GetHashCode(): 54267293
Print lrc2 hash code -- lrc2.GetHashCode(): 18643596
LoginResourceRecord implements IEquatableT: True
LoginResourceClass implements IEquatableT: False
Print LoginResourceRecord.ToString -- lrr1.ToString(): LoginResourceRecord { Username Lion-O, Password jaga, RememberMe True }
Print LoginResourceClass.ToString -- lrc1.ToString(): LoginResourceClass
Record syntax有多种用于声明records的用例在使用过每种方式后我们就会对每一种模式的好处有所了解我们还能看到不同方式他们不是不同的语法而是多种选择。第一个方式是最简单的但是它的灵活性比较小它适用于具有少量必需属性的records。下面是前面显示的LoginResource record作为此模式的一个示例。这一行是的定义public record LoginResource(string Username, string Password, bool RememberMe);
构造遵循具有参数的构造函数的要求包括允许使用可选参数。var login new LoginResource(Lion-O, jaga, true);
还可以使用目标类型。LoginResource login new(Lion-O, jaga, true);
下一个语法使所有属性都是可选的。为record提供了一个隐式无参数构造函数。public record LoginResource
{public string Username {get; init;}public string Password {get; init;}public bool RememberMe {get; init;}
}
构造使用对象初始化器看起来像下面这样LoginResource login new()
{Username Lion-O,TemperatureC jaga
};
如果我们想让这两个属性是必须的另一个是可选属性那么我们可以通过如下方式实现public record LoginResource(string Username, string Password)
{public bool RememberMe {get; init;}
}
构造可能如下所示其中未指定RememberMeLoginResource login new(Lion-O, jaga);
如果说要指定RememberMe可以通过如下方式来实现LoginResource login new(Lion-O, jaga)
{RememberMe true
};
如果说我们不认为record只用于不可变数据那么我们可以选择公开可变属性如下代码片段所示该片段展示了关于电池的信息。Model和TotalCapacityAmpHours属性是不可变的而剩余的容量百分比是可变的。using System;Battery battery new Battery(CR2032, 0.235)
{RemainingCapacityPercentage 100
};Console.WriteLine (battery);for (int i battery.RemainingCapacityPercentage; i 0; i--)
{battery.RemainingCapacityPercentage i;
}Console.WriteLine (battery);public record Battery(string Model, double TotalCapacityAmpHours)
{public int RemainingCapacityPercentage {get;set;}
}
输出结果如下所示richthundera recordmutable % dotnet run
Battery { Model CR2032, TotalCapacityAmpHours 0.235, RemainingCapacityPercentage 100 }
Battery { Model CR2032, TotalCapacityAmpHours 0.235, RemainingCapacityPercentage 0 }
Non-destructive record mutation不变性是给我们带来了很多的好处但是我们也很快的发现了需要修改record的情况在不放弃record的情况下我们该如何处理这种情况呢with表达式可以满足这些需求它可以根据相同类型的现有record来创建新record我们可以指定想要的不同的新值并从现有的record中复制所有其他属性.现在我们有个需求就是将用户名转换为小写这样的情况下我们才可以将其保存到我们的数据库中如果说处理这个需求我们可能会像如下代码片段中这样去处理LoginResource login new(Lion-O, jaga, true);
LoginResource loginLowercased lrr1 with {Username login.Username.ToLowerInvariant()};
登录record没有被更改事实上这是不可能的转换只影响了loginLowercased除了小写转换为loginLowercased之外其他与登录相同。我们可以使用内置的ToString()覆盖检查with是否完成了预期的工作。Console.WriteLine(login);
Console.WriteLine(loginLowercased);
下面代码是输出LoginResource { Username Lion-O, Password jaga, RememberMe True }
LoginResource { Username lion-o, Password jaga, RememberMe True }
我们可以进一步的了解with的工作原理它将所有的值从一条record复制到另一条record。这不是一个record依赖于另一个record的委托模型。事实上with操作完成后两个record之间就没有关系了只对record的构建有意义这就意味着对于引用类型副本只是引用副本。对于值类型复制值.您可以使用以下代码查看该语义。Console.WriteLine($Record equality: {login loginLowercased});
Console.WriteLine($Property equality: Username {login.Username loginLowercased.Username}; Password {login.Password loginLowercased.Password}; RememberMe {login.RememberMe loginLowercased.RememberMe});
输出Record equality: False
Property equality: Username False; Password True; RememberMe True
Record inheritance扩展record很容易假设一个新的LastLoggedIn属性可以将其直接添加到LoginResource,record不像传统的接口那样脆弱除非我们想创建需要构造函数参数的新属性.这个新的record可以基于如下的LoginResourcepublic record LoginResource(string Username, string Password)
{public bool RememberMe {get; init;}
}
新的record可能就是如下这样public record LoginWithUserDataResource(string Username, string Password, DateTime LastLoggedIn) : LoginResource(Username, Password)
{public int DiscountTier {get; init};public bool FreeShipping {get; init};
}
现在已经将LastLoggedIn设置为一个必须的属性并且也增加了可选的属性Modeling record construction helpers我们一起来看另一个例子测量体重体重的测量来自一个互联网的秤重量是以公斤来指定的但是某些情况下重点需要以磅来提供。可以通过如下代码片段进行声明public record WeightMeasurement(DateTime Date, int Kilograms)
{public int Pounds {get; init;}public static int GetPounds(int kilograms) kilograms * 2.20462262;
}
这就是构造的样子var weight 200;
WeightMeasurement measurement new(DateTime.Now, weight)
{Pounds WeightMeasurement.GetPounds(weight)
};
在本例中有必要将权重指定为local。不可能在对象初始化器中访问公斤属性。还需要将GetPounds定义为静态方法。不可能在对象初始化器中调用实例方法(对于正在构造的类型)。Records and Nullability一切都是不可变的那么空值从何而来?不完全是。不可变属性可以是null并且在这种情况下将始终是null。让我们看看另一个没有启用可空性的程序。using System;
using System.Collections.Generic;Author author new(null, null);Console.WriteLine(author.Name.ToString());public record Author(string Name, ListBook Books)
{public string Website {get; init;}public string Genre {get; init;}public ListAuthor RelatedAuthors {get; init;}
}public record Book(string name, int Published, Author author);
这个程序将编译并抛出一个NullReference异常这是由于取消引用author.Name为空。为了进一步说明这一点将不编译以下内容。author.Name 初始化为null然后不能更改因为属性是不可变的。Author author new(null, null);
author.Name Colin Meloy;
下面启动可空性Project SdkMicrosoft.NET.SdkPropertyGroupOutputTypeExe/OutputTypeTargetFrameworknet5.0/TargetFrameworkLangVersionpreview/LangVersionNullableenable/Nullable/PropertyGroup/Project
下面我们能看到一堆这样的警告/Users/rich/recordsnullability/Program.cs(8,21): warning CS8618: Non-nullable property Website must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [/Users/rich/recordsnullability/recordsnullability.csproj]
用null注释更新了Author record这些注释描述了我打算使用的record。public record Author(string Name, ListBook Books)
{public string? Website {get; init;}public string? Genre {get; init;}public ListAuthor? RelatedAuthors {get; init;}
}
仍然得到了对null的警告null构造的Author之前看到。/Users/rich/recordsnullability/Program.cs(5,21): warning CS8625: Cannot convert null literal to non-nullable reference type. [/Users/rich/recordsnullability/recordsnullability.csproj]很好因为我们想避免这种情况。现在下面展示该程序的更新版本该版本可以很好地运行并享有可空性的好处。using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;Author lord new Author(Karen Lord)
{Website https://karenlord.wordpress.com/,RelatedAuthors new()
};lord.Books.AddRange(new Book[]{new Book(The Best of All Possible Worlds, 2013, lord),new Book(The Galaxy Game, 2015, lord)}
);lord.RelatedAuthors.AddRange(new Author[]{new (Nalo Hopkinson),new (Ursula K. Le Guin),new (Orson Scott Card),new (Patrick Rothfuss)}
);Console.WriteLine($Author: {lord.Name});
Console.WriteLine($Books: {lord.Books.Count});
Console.WriteLine($Related authors: {lord.RelatedAuthors.Count});public record Author(string Name)
{private ListBook _books new();public ListBook Books _books;public string? Website {get; init;}public string? Genre {get; init;}public ListAuthor? RelatedAuthors {get; init;}
}public record Book(string name, int Published, Author author);
该程序在编译时不会出现可空的警告。大家可能对下面这句有疑惑lord.RelatedAuthors.AddRange(
Author.RelatedAuthors可以为null。编译器可以看到RelatedAuthors属性的设置只是前面几行因此它知道RelatedAuthors引用将为非null。但是想象一下这个程序看起来是这样的。Author GetAuthor()
{return new Author(Karen Lord){Website https://karenlord.wordpress.com/,RelatedAuthors new()};
}Author lord GetAuthor();
编译器没有流程分析技巧无法知道当类型构造在单独的方法中时RelatedAuthor将为非空。在这种情况下将需要以下两种模式之一lord.RelatedAuthors!.AddRange(
orif (lord.RelatedAuthors is object)
{lord.RelatedAuthors.AddRange( ...
}
这是一个关于记录可空性的冗长演示只是为了说明它不会改变使用可空引用类型的任何体验。另外您可能已经注意到我将Author record上的Books属性移动为初始化的get-only属性而不是记录构造函数中的必需参数。这是由于作者与书籍之间存在循环关系。不变性和循环引用可能会引起头痛。在这种情况下可以并且仅表示需要在Book对象之前创建所有Author对象。结果无法提供完全初始化的Book对象集作为Author结构的一部分。作为Author结构的一部分我们可以期望的最好的是一个空的List。结果初始化空的List作为Author结构的一部分似乎是最佳选择。没有规则要求所有这些属性都必须是init样式。这样做只是为了演示该行为。我们将过渡到谈论JSON序列化。这个带有循环引用的示例与不久之后的在JSON对象图中保存引用有关。JsonSerializer支持带有循环引用的对象图但不支持带有参数化构造函数的类型。您可以将Author对象序列化为JSON但不能序列化为当前定义的Author对象。如果Author不是记录或没有循环引用那么JsonSerializer可以同时进行序列化和反序列化。System.Text.Json.NET 5.0中对System.Text.Json进行了显着改进以提高性能可靠性当然如果熟悉Newtonsoft.Json那么用起来更容易 它还包括对将JSON对象反序列化为记录的支持本文前面已介绍了新的C功能如果要使用System.Text.Json替代Newtonsoft.Json则应查看迁移指南。该指南阐明了这两个API之间的关系。System.Text.Json旨在涵盖与Newtonsoft.Json相同的许多场景但并不旨在替代流行的JSON库或与流行的JSON库实现功能对等。我们尝试在性能和可用性之间保持平衡并在设计选择中偏向性能。HttpClient extension methodsJsonSerializer扩展方法现在在HttpClient上公开并且极大地简化了同时使用这两个api。这些扩展方法消除了复杂性并为您处理各种场景包括处理内容流和验证内容媒体类型。Steve Gordon很好地解释了使用带有System.Net.Http.Json的HttpClient发送和接收JSON的好处。下面的示例使用新的GetFromJsonAsync()扩展方法将天气预报JSON数据反序列化为预报记录。using System;
using System.Net.Http;
using System.Net.Http.Json;string serviceURL https://localhost:5001/WeatherForecast;
HttpClient client new();
Forecast[] forecasts await client.GetFromJsonAsyncForecast[](serviceURL);foreach(Forecast forecast in forecasts)
{Console.WriteLine(${forecast.Date}; {forecast.TemperatureC}C; {forecast.Summary});
}// {date:2020-09-06T11:31:01.923395-07:00,temperatureC:-1,temperatureF:31,summary:Scorching}
public record Forecast(DateTime Date, int TemperatureC, int TemperatureF, string Summary);
这段代码非常紧凑!它依赖于来自c#9的顶级程序和record以及新的GetFromJsonAsync()扩展方法。在foreach和await的使用中可能大家会怀疑是否对流JSON对象的支持在未来版本中是支持的。大家可以在自己的机器上试试。下面的.NET SDK命令将使用WebAPI模板创建一个天气预报服务。默认情况下它将在以下URL公开服务:https://localhost:5001/WeatherForecast。这与示例中使用的URL相同。richthundera ~ % dotnet new webapi -o webapi
richthundera ~ % cd webapi
richthundera webapi % dotnet run
确保已经运行dotnet dev-certs https——首先信任否则客户端和服务器之间的握手将不起作用。如果有问题请参见信任ASP.NET Core HTTPS开发证书。然后可以运行前面的示例。richthundera ~ % git clone https://gist.github.com/3b41d7496f2d8533b2d88896bd31e764.git weather-forecast
richthundera ~ % cd weather-forecast
richthundera weather-forecast % dotnet run
9/9/2020 12:09:19 PM; 24C; Chilly
9/10/2020 12:09:19 PM; 54C; Mild
9/11/2020 12:09:19 PM; -2C; Hot
9/12/2020 12:09:19 PM; 24C; Cool
9/13/2020 12:09:19 PM; 45C; Balmy
Improved support for immutable types其实定义不可变类型有多种方式records只是最新的一种JsonSerializer现在支持不可变类型在下面示例中我们将看到带有不可变结构的序列化using System;
using System.Text.Json;
using System.Text.Json.Serialization;var json {\date\:\2020-09-06T11:31:01.923395-07:00\,\temperatureC\:-1,\temperatureF\:31,\summary\:\Scorching\} ;
var options new JsonSerializerOptions()
{PropertyNameCaseInsensitive true,IncludeFields true,PropertyNamingPolicy JsonNamingPolicy.CamelCase
};
var forecast JsonSerializer.DeserializeForecast(json, options);Console.WriteLine(forecast.Date);
Console.WriteLine(forecast.TemperatureC);
Console.WriteLine(forecast.TemperatureF);
Console.WriteLine(forecast.Summary);var roundTrippedJson JsonSerializer.SerializeForecast(forecast, options);Console.WriteLine(roundTrippedJson);public struct Forecast{public DateTime Date {get;}public int TemperatureC {get;}public int TemperatureF {get;}public string Summary {get;}[JsonConstructor]public Forecast(DateTime date, int temperatureC, int temperatureF, string summary) (Date, TemperatureC, TemperatureF, Summary) (date, temperatureC, temperatureF, summary);
}
注意JsonConstructor属性需要指定与struct一起使用的构造函数对于类如果只有一个构造函数那么属性就不是必须的与records相同。输出内容richthundera jsonserializerimmutabletypes % dotnet run
9/6/2020 11:31:01 AM
-1
31
Scorching
{date:2020-09-06T11:31:01.923395-07:00,temperatureC:-1,temperatureF:31,summary:Scorching}
Support for recordsJsonSerializer对records的支持与上面展示的不可变类型的支持几乎相同我想在这里显示的区别是将JSON对象反序列化为一条records该records公开了参数化的构造函数和可选的init属性。在下面代码片段中包含了对records的定义using System;
using System.Text.Json;Forecast forecast new(DateTime.Now, 40)
{Summary Hot!
};string forecastJson JsonSerializer.SerializeForecast(forecast);
Console.WriteLine(forecastJson);
Forecast? forecastObj JsonSerializer.DeserializeForecast(forecastJson);
Console.Write(forecastObj);public record Forecast (DateTime Date, int TemperatureC)
{public string? Summary {get; init;}
};
输出如下所示richthundera jsonserializerrecords % dotnet run
{Date:2020-09-12T18:24:47.053821-07:00,TemperatureC:40,Summary:Hot!}
Forecast { Date 9/12/2020 6:24:47 PM, TemperatureC 40, Summary Hot! }
Improved DictionaryK,V supportJsonSerializer现在支持具有非字符串键的字典。我们可以在下面的示例中看到它的样子。在.NET Core 3.0中这段代码可以编译但会抛出NotSupportedException异常。using System;
using System.Collections.Generic;
using System.Text.Json;Dictionaryint, string numbers new ()
{{0, zero},{1, one},{2, two},{3, three},{5, five},{8, eight},{13, thirteen},{21, twenty one},{34, thirty four},{55, fifty five},
};var json JsonSerializer.SerializeDictionaryint, string(numbers);Console.WriteLine(json);var dictionary JsonSerializer.DeserializeDictionaryint, string(json);Console.WriteLine(dictionary[55]);
输出内容richthundera jsondictionarykeys % dotnet run
{0:zero,1:one,2:two,3:three,5:five,8:eight,13:thirteen,21:twenty one,34:thirty four,55:fifty five}
fifty five
Support for fieldsJsonSerializer现在支持字段。我们可以在下面的示例中看到它的样子。在.NET Core 3.0中JsonSerializer无法对使用字段的类型进行序列化或反序列化。对于具有字段且无法更改的现有类型来说这是一个问题。有了这个支持这不再是一个问题。using System;
using System.Text.Json;var json {\date\:\2020-09-06T11:31:01.923395-07:00\,\temperatureC\:-1,\temperatureF\:31,\summary\:\Scorching\} ;
var options new JsonSerializerOptions()
{PropertyNameCaseInsensitive true,IncludeFields true,PropertyNamingPolicy JsonNamingPolicy.CamelCase
};
var forecast JsonSerializer.DeserializeForecast(json, options);Console.WriteLine(forecast.Date);
Console.WriteLine(forecast.TemperatureC);
Console.WriteLine(forecast.TemperatureF);
Console.WriteLine(forecast.Summary);var roundTrippedJson JsonSerializer.SerializeForecast(forecast, options);Console.WriteLine(roundTrippedJson);public class Forecast{public DateTime Date;public int TemperatureC;public int TemperatureF;public string Summary;
}
输出内容richthundera jsonserializerfields % dotnet run
9/6/2020 11:31:01 AM
-1
31
Scorching
{date:2020-09-06T11:31:01.923395-07:00,temperatureC:-1,temperatureF:31,summary:Scorching}
Preserving references in JSON object graphsJsonSerializer增加了对在JSON对象图中保存(循环)引用的支持。它通过存储在将JSON字符串反序列化回对象时可以重新构建的id来实现这一点。using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;Employee janeEmployee new()
{Name Jane Doe,YearsEmployed 10
};Employee johnEmployee new()
{Name John Smith
};janeEmployee.Reports new ListEmployee { johnEmployee };
johnEmployee.Manager janeEmployee;JsonSerializerOptions options new()
{// NEW: globally ignore default values when writing null or defaultDefaultIgnoreCondition JsonIgnoreCondition.WhenWritingDefault,// NEW: globally allow reading and writing numbers as JSON stringsNumberHandling JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString,// NEW: globally support preserving object references when (de)serializingReferenceHandler ReferenceHandler.Preserve,IncludeFields true, // NEW: globally include fields for (de)serializationWriteIndented true,};string serialized JsonSerializer.Serialize(janeEmployee, options);
Console.WriteLine($Jane serialized: {serialized});Employee janeDeserialized JsonSerializer.DeserializeEmployee(serialized, options);
Console.Write(Whether Janes first reports manager is Jane: );
Console.WriteLine(janeDeserialized.Reports[0].Manager janeDeserialized);public class Employee
{// NEW: Allows use of non-public property accessor.// Can also be used to include fields per-field, rather than globally with JsonSerializerOptions.[JsonInclude]public string Name { get; internal set; }public Employee Manager { get; set; }public ListEmployee Reports;public int YearsEmployed { get; set; }// NEW: Always include when (de)serializing regardless of global options[JsonIgnore(Condition JsonIgnoreCondition.Never)]public bool IsManager Reports?.Count 0;
}
Performance在.NET 5.0中JsonSerializer的性能得到了显着改善。Stephen Toub在.NET 5中的Performance Improvements中涵盖了JsonSerializer的一些改进。我会在这里再介绍几个。Collections (de)serialization本次对大型集合做了显著的改进(反序列化时为1.15x-1.5x序列化时为1.5x-2.4x)。我们可以在dotnet/runtime #2259中更详细地看到这些改进。将.NET 5.0与.NET Core 3.1进行比较对List反序列化的改进特别令人印象深刻。这些变化将在高性能应用程序中非常有意义。MethodMeanErrorStdDevMedianMinMaxGen 0Gen 1Gen 2AllocatedDeserialize before76.40 us0.392 us0.366 us76.37 us75.53 us76.87 us1.2169––8.25 KBAfter ~1.5x faster50.05 us0.251 us0.235 us49.94 us49.76 us50.43 us1.3922––8.62 KBSerialize before29.04 us0.213 us0.189 us29.00 us28.70 us29.34 us1.2620––8.07 KBAfter ~2.4x faster12.17 us0.205 us0.191 us12.15 us11.97 us12.55 us1.3187––8.34 KBProperty lookups — naming convention使用JSON最常见的问题之一是命名规范与.NET设计准则不匹配。JSON属性通常是camelCase .NET属性和字段通常是PascalCase。我们使用的json序列化器负责在命名约定之间架桥。这不是免费的至少对.NET Core 3.1来说不是。在.NET5中这种成本现在可以忽略不计了。.NET 5.0中大大改进了允许缺少属性和不区分大小写的代码。在某些情况下速度快约1.75倍。下面是一个简单的4个属性测试类的基准测试它的属性名为7 bytes。3.1 performance
| Method | Mean | Error | StdDev | Median | Min | Max | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------------------------------- |-----------:|--------:|--------:|-----------:|-----------:|-----------:|-------:|------:|------:|----------:|
| CaseSensitive_Matching | 844.2 ns | 4.25 ns | 3.55 ns | 844.2 ns | 838.6 ns | 850.6 ns | 0.0342 | - | - | 224 B |
| CaseInsensitive_Matching | 833.3 ns | 3.84 ns | 3.40 ns | 832.6 ns | 829.4 ns | 841.1 ns | 0.0504 | - | - | 328 B |
| CaseSensitive_NotMatching(Missing)| 1,007.7 ns | 9.40 ns | 8.79 ns | 1,005.1 ns | 997.3 ns | 1,023.3 ns | 0.0722 | - | - | 464 B |
| CaseInsensitive_NotMatching | 1,405.6 ns | 8.35 ns | 7.40 ns | 1,405.1 ns | 1,397.1 ns | 1,423.6 ns | 0.0626 | - | - | 408 B |5.0 performance
| Method | Mean | Error | StdDev | Median | Min | Max | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------------------------------- |---------:|--------:|--------:|---------:|---------:|---------:|-------:|------:|------:|----------:|
| CaseSensitive_Matching | 799.2 ns | 4.59 ns | 4.29 ns | 801.0 ns | 790.5 ns | 803.9 ns | 0.0985 | - | - | 632 B |
| CaseInsensitive_Matching | 789.2 ns | 6.62 ns | 5.53 ns | 790.3 ns | 776.0 ns | 794.4 ns | 0.1004 | - | - | 632 B |
| CaseSensitive_NotMatching(Missing)| 479.9 ns | 0.75 ns | 0.59 ns | 479.8 ns | 479.1 ns | 481.0 ns | 0.0059 | - | - | 40 B |
| CaseInsensitive_NotMatching | 783.5 ns | 3.26 ns | 2.89 ns | 783.5 ns | 779.0 ns | 789.2 ns | 0.1004 | - | - | 632 B |
TechEmpower improvement开发团队在TechEmpower基准测试中花费了大量的精力来改进.NET的性能。使用TechEmpower JSON基准来验证这些JsonSerializer改进是很有意义的。现在性能提高了~ 19%一旦我们将条目更新到.NET5这将提高.NET5在基准测试中的位置。这个版本的目标是与netty相比更具竞争力netty是一种常见的Java web服务器。在dotnet/runtime #37976中详细介绍了这些更改和性能度量。这里有两套基准。第一个是使用团队维护的JsonSerializer性能基准测试来验证性能。观察到有~8%的改善。下一部分是关于技术授权的。它测量了满足TechEmpower JSON基准测试要求的三种不同方法。SerializeWithCachedBufferAndWriter是我们在官方基准测试中使用的MethodMeanErrorStdDevMedianMinMaxGen 0Gen 1Gen 2AllocatedSerializeWithCachedBufferAndWriter (before)155.3 ns1.19 ns1.11 ns155.5 ns153.3 ns157.3 ns0.0038––24 BSerializeWithCachedBufferAndWriter (after)130.8 ns1.50 ns1.40 ns130.9 ns128.6 ns133.0 ns0.0037––24 B如果我们看一下Min列我们可以做一些简单的数学计算:153.3/128.6 ~1.19。提高了19%。Closing本文对records和JsonSerializer有了一个更好的认识。它们只是.NET 5.0众多改进中的两个。preivew 8的文章涵盖了更大的特性集这为5.0的价值提供了更广阔的视角。正如我们所知道的他们现在没有在.NET 5.0中添加任何新特性。这些后期的预览和RC的文章来涵盖开发团队已经建立的所有功能。当然大家可以在原文中进行留言说一下在期望RC2中开发团队这边需要详细介绍的特性。原文https://devblogs.microsoft.com/dotnet/announcing-net-5-0-rc-1/
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/89893.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!