.NET 记录多框架下的Json序列化属性标记问题
<p>有小伙伴反馈,System.Text.Json使用的序列化问题,经了解是System.Text.Json不兼容System.Runtime.Serialization.DataMemenber属性标记</p><p>来个demo,</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">var</span> testMode = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> TestMode();
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> testMode.ID = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">aaa</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 255, 1)">var</span> serialize =<span style="color: rgba(0, 0, 0, 1)"> JsonSerializer.Serialize(testMode);
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)">Debug.WriteLine(serialize);
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)">
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> TestMode
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> ID { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 128, 128, 1)">11</span> }</pre>
</div>
<p><img src="https://img2024.cnblogs.com/blog/685541/202505/685541-20250526144401894-1248465193.png" alt="" loading="lazy"></p>
<p>所以DataMember是不适用system.Text.Json的。</p>
<p>我们梳理下各序列化方案下如何正确的使用属性标记</p>
<h3>DataContract及DataMemenber</h3>
<p>System.Runtime.Serialization下,有数据契约序列化DataContractSerializer,可以用于XML序列化及WCF数据传输</p>
<p>而它的胞弟Json序列化DataContractJsonSerializer,是早期 的.NET Json序列化方案。因性能较弱,Framework下大家逐渐使用NewtonSoft.Json来替换。但简单的Json序列化,依然可以使用DataContractJsonSerializer</p>
<p>DataContractJsonSerializer使用的属性标记是DataContract、DataMember,DataContract用于标记类,DataMember标记序列化的属性:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">var</span> stopwatch = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Stopwatch();
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 0, 1)">stopwatch.Start();
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 255, 1)">var</span> serializer = <span style="color: rgba(0, 0, 255, 1)">new</span> DataContractJsonSerializer(<span style="color: rgba(0, 0, 255, 1)">typeof</span><span style="color: rgba(0, 0, 0, 1)">(TestMode));
</span><span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> stream = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MemoryStream())
</span><span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)">6</span> <span style="color: rgba(0, 0, 0, 1)"> serializer.WriteObject(stream, testMode);
</span><span style="color: rgba(0, 128, 128, 1)">7</span> <span style="color: rgba(0, 0, 255, 1)">string</span> json =<span style="color: rgba(0, 0, 0, 1)"> Encoding.UTF8.GetString(stream.ToArray());
</span><span style="color: rgba(0, 128, 128, 1)">8</span> Console.WriteLine($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{json},{stopwatch.ElapsedMilliseconds}ms</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">9</span> }</pre>
</div>
<p><strong>Newtonsoft.Json是兼容DataContract、DataMember的</strong>,所以使用Newtonsoft.Json.JsonConvert可以正常的进行对DataMember的属性进行序列化。:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 0, 1)">stopwatch.Restart();
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 255, 1)">var</span> serializeObject =<span style="color: rgba(0, 0, 0, 1)"> JsonConvert.SerializeObject(testMode);
</span><span style="color: rgba(0, 128, 128, 1)">3</span> Console.WriteLine($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{serializeObject},{stopwatch.ElapsedMilliseconds}ms</span><span style="color: rgba(128, 0, 0, 1)">"</span>);</pre>
</div>
<p>Newtonsoft.Json内部是通过默认配置JsonConvert.DefaultSettings,来兼容DataContract标记,</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">var</span> settings = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> JsonSerializerSettings
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)">3</span> ContractResolver = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> DefaultContractResolver
</span><span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">5</span> IgnoreSerializableAttribute = <span style="color: rgba(0, 0, 255, 1)">false</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 启用 DataContract 支持</span>
<span style="color: rgba(0, 128, 128, 1)">6</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">7</span> };</pre>
</div>
<p>Newtonsoft.Json虽然对DataMember兼容,但DataContract标记需要注意下:类加DataContract标记后,则只支持有标记DataMember的属性序列化。</p>
<p>输出结果:</p>
<p><img src="https://img2024.cnblogs.com/blog/685541/202505/685541-20250526150858685-1459921338.png" alt="" loading="lazy"></p>
<p>DataMember均序列化正常。另外可以发现,在.NET Framework及.NET版本下,<strong>首次序列化性能</strong>DataContractJsonSerializer比NewtonSoft.Json好很多</p>
<p>System.Text.Json被称作现代Json序列化,System.Text.Json 不识别 ,如果必须兼容可通过自定义 JsonConverter 间接支持,但复杂。。不推荐</p>
<p>补充下DataMember使用的其它相关标记:</p>
<p> - 忽略字段</p>
<p>EmitDefaultValue、Order、IsRequired - 控制默认值、排序、是否必填</p>
<p>我个人挺喜欢用DataContract的,可以明确标记序列化类,与业务数据类隔离开来。</p>
<h3>JsonPropertyName</h3>
<p>JsonPropertyName是System.Text.Json.Serialization命名空间下的Attribute类,<strong>只适用于JsonSerializer序列化方案</strong></p>
<p>微软官方推荐使用,性能比Newtonsoft.Json更好。性能对比可参考 .NET Json序列化方案选择 - 唐宋元明清2188 - 博客园</p>
<p>也补充相关属性标记:</p>
<p> - 忽略属性</p>
<p> - 必填</p>
<p> - 强制包含如private的私有字段</p>
<h3>JsonProperty</h3>
<p>JsonProerty是Newtonsoft.Json第三方组件下的属性标记类,专属Newtonsoft.Json-JsonConvert序列化方案</p>
<p>补充相关属性标记</p>
<p> - 忽略属性</p>
<p> - 必填</p>
<p>Newtonsoft.Json与System.Text.Json属性标记很相似,不要混用了。</p>
<h3>多框架下的属性标记</h3>
<p>如果你的组件添加了.NETFramework以及.NET多个框架版本,因考虑不同框架下的最佳Json序列化性能,那你的序列化属性类可能就需要处理不同的属性标记了</p>
<p>同时给一个属性添加多个标记能解决问题:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span>
</span><span style="color: rgba(0, 128, 128, 1)">2</span>
</span><span style="color: rgba(0, 128, 128, 1)">3</span>
</span><span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> ID { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span>; }</pre>
</div>
<p>但不建议,容易造成后续维护的风险,可能不小心就遗漏了一个。</p>
<p>最佳方案是,通过明确的框架类型来区分不同代码</p>
<p>引用组件:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">#if</span> NETFRAMEWORK
<span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Newtonsoft.Json;
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 255, 1)">#elif</span> NET8_0
<span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Text.Json.Serialization;
</span><span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 255, 1)">#endif</span></pre>
</div>
<p>添加序列化属性标记:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">#if</span> NETFRAMEWORK
<span style="color: rgba(0, 128, 128, 1)">2</span>
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 255, 1)">#elif</span> NET8_0
<span style="color: rgba(0, 128, 128, 1)">4</span>
</span><span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 255, 1)">#endif</span></pre>
</div>
<p>一个框架下,建议明确并统一使用一个序列化方案。性能对比可参考 .NET Json序列化方案选择 - 唐宋元明清2188 - 博客园</p>
</div>
<div id="MySignature" role="contentinfo">
<div>作者:唐宋元明清2188</div>
<div>出处:http://www.cnblogs.com/kybs0/</div>
<div>让学习成为习惯,假设明天就有重大机遇等着你,你准备好了么</div>
<div>本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。 </div><br><br>
来源:https://www.cnblogs.com/kybs0/p/18896851
頁:
[1]