当前位置: 首页 > 编程语言 > C#

NewtonSoftJsonConverter-访问其他属性分享

时间:2023-04-10 14:10:00 C#

NewtonSoftJsonConverter-访问其他属性我需要将十进制的输出json格式化为货币,culture指定我正在序列化的对象,可以嵌套,所以我无法在序列化程序中预设选项。我目前的做法是使用一个额外的字符串属性来格式化输出。[JsonIgnore]publicdecimalCost{get;set;}[JsonIgnore]publicCultureInfoCulture{get;set;}publicstringAsCurrency(decimalvalue){returnstring.Format(this.Culture,"{0:c}",value);}[JsonProperty("FormattedCost")]publicstringFormattedCost{get{returnthis.AsCurrency(this.Cost);我有很多属性要处理,我不关心反序列化,JsonObject被不同的语言用来填充PDF,所以我想要字符串值。理想情况下,我想要一个JsonConverter,这样我就可以做[JsonProperty("FormattedCost")][JsonConverter(typeof(MyCurrencyConverter))]publicdecimalCost{get;set;}我遇到的问题是如何访问转换器包含对象的Culture属性。publicclassMyCurrencyConverter:JsonConverter{publicoverridevoidWriteJson(JsonWriterwriter,objectvalue,JsonSerializerserializer){varculture=//如何从父对象获取Culture?writer.WriteValue(string.format(culture,"{0:c}",(decimal)value);}publicoverrideobjectReadJson(JsonReaderreader,TypeobjectType,objectexistingValue,JsonSerializerserializer){thrownewNotImplementedException();}publicoverrideboolCanConvert(TypeobjectType){returntypeof()==objectType;}}根据要求采样JSON。对于一组类,每个类都有成本和文化。[{FormattedCost:"£5000.00"},{FormattedCost:"$8000.00"},{FormattedCost:"599.00"}]实际对象要复杂得多,嵌套资产的多个字段每个都有自己的数字。另外,并非所有小数都是货币。我真的不想要为合同本身编写自定义序列化程序,因为每次属性更改时我都必须修改它。理想的解决方案是能够使用转换器属性标记某些十进制属性,以便它可以处理它。另一种方式我会like是使用decimal到decimal属性的隐式转换创建一个自定义类,但它变得更加复杂,因为某些属性是根据以前的结果计算的属性。替代方法我有一个针对我的用例的解决方案,但它使用反射来在序列化程序变量中获取私有。var绑定=BindingFlags.NonPublic|BindingFlags.Instance;varwriter=serializer.GetType().GetMethod("GetInternalSerializer",binding)?.Invoke(serializer,null);varparent=writer?.GetType().GetField("_serializeStack",binding)?.GetValue(writer)isListstack&&stack.Count>1?stack[stack.Count-2]asMyType:null;在我测试过的用例中,这给了我父对象,但它没有使用公共API。您要做的是在序列化对象时拦截并修改对象特定属性的值,同时对所有其他属性使用默认序列化。这可以通过自定义ContractResolver来完成,该自定义ContractResolver在应用特定属性时替换相关属性的ValueProvider。首先,定义以下属性和统一解析程序:[System.AttributeUsage(System.AttributeTargets.Property|System.AttributeTargets.Field,AllowMultiple=false)]publicclassJsonFormatAttribute:System.Attribute{publicJsonFormatAttribute(stringformattingString){this.FormattingString=格式化字符串;}//////传递给string.Format()的格式字符串///publicstringFormattingString{get;放;}//////返回对象文化的基础属性的名称,如果不适用则返回NULL。///publicstringCulturePropertyName{get;放;}}publicclassFormattedPropertyContractResolver:DefaultContractResolver{protectedoverrideIListCreateProperties(Typetype,MemberSerializationmemberSerialization){returnbase.CreateProperties(type,memberSerialization).AddFormatting();}}}publicstaticclassJsonContractExtensions{classFormattedValueProvider:IValueProvider{readonlyIValueProviderbaseProvider;只读字符串格式字符串;只读IValueProvider文化价值提供者;publicFormattedValueProvider(IValueProviderbaseProvider,stringformatString,IValueProvidercultureValueProvider){this.baseProvider=baseProvider;this.formatString=formatString;this.cultureValueProvider=cultureValueProvider;}#regionIValueProviderMemberspublicobjectGetValue(objecttarget){varvalue=baseProvider.GetValue(target);varculture=cultureValueProvider==null?null:(CultureInfo)cultureValueProvider.GetValue(target);返回string.Format(culture??CultureInfo.InvariantCulture,formatString,value);}publicvoidSetValue(objecttarget,objectvalue){//这个契约解析器应该只用于序列化,而不是反序列化,所以抛出异常。抛出新的NotImplementedException();}#endregion}publicstaticIListAddFormatting(这个IList属性){ILookuplookup=null;foreach(varjsonPropertyinproperties){varattr=(JsonFormatAttribute)jsonProperty.AttributeProvider.GetAttributes(typeof(JsonFormatAttribute),false).SingleOrDefault();if(attr!=null){IValueProvidercultureValueProvider=null;如果(attr.CulturePropertyName!=null){如果(lookup==null)lookup=properties.ToLookup(p=>p.UnderlyingName);varcultureProperty=lookup[attr.CulturePropertyName].FirstOrDefault();如果(cultureProperty!=null)cultureValueProvider=cultureProperty.ValueProvider;}jsonProperty.ValueProvider=newFormattedValueProvider(jsonProperty.ValueProvider,attr.FormattingString,cultureValueProvider);jsonProperty.PropertyType=typeof(字符串);}}返回属性;}}接下来,按如下方式确定对象:publicclassRootObject{[JsonFormat("{0:c}",CulturePropertyName=nameof(Culture))]publicdecimalCost{get;放;}[JsonIgnore]publicCultureInfo文化{get;放;}publicstringSomeValue{get;放;}publicstringSomeOtherValue{get;放;}}最后,顺序化如下:varsettings=newJsonSerializerSettings{ContractResolver=newFormattedPropertyContractResolver{NamingStrategy=newCamelCaseNamingStrategy(),},};varjson=JsonConvert.SerializeObject(root,Formatting.Indented,settings);注意:由于您没有序列化文化名称,我没有看到任何反序列化成本属性的方法所以,我从SetValue方法中抛出异常。(此外,即使您正在序列化区域性名称,由于根据标准JSON对象是名称/值对的无序集合,因此无法保证区域性名称会在反序列化JSON之前出现。这可能与whyNewtonsoftdoesn'tprovidesaccesstotheparentstack.Duringdeserialization,therearenotguaranteethatrequiredpropertiesintheparenthierarchyhasbeenread–orevenconstructed.)如果必须将多个不同的自定义规则应用于合同,请考虑使用如何添加元数据以描述JSON.Net中的哪些属性是日期中的ConfigurableContractResolver。您可能希望缓存合同解析器以获得最佳性能。另一种方法是向父对象添加一个转换器,通过暂时禁用自身、调整返回的JObject,然后将其写出,生成JObject的默认序列化。有关此方法的示例,请参阅使用[JsonConvert()]时JSON.NetthrowsStackOverflowException或CanIuseJson.nettoserializenestedpropertiestomyclassinoneoperation?.在您写的评论中,在WriteJson内部,我不知道如何访问父对象及其属性。应该可以使用自定义IValueProvider来执行此操作,该自定义IValueProvider返回包??含父JsonConverter和值的Tuple或类似物,它将与期望此类输入的特定JsonConverter一起使用。不确定我会推荐这个,因为它非常棘手。工作示例.Net小提琴。以上就是C#学习教程:NewtonSoftJsonConverter-获取其他属性共享的所有内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权请点击右侧联系管理员删除。如需转载请注明出处: