在Newtonsoft.Json中添加多个合同解析器

数据结构蓝图:

public class Movie { public string Name { get; set; } } 

使用Newtonsoft.Json,我有以下Json序列化配置。

 var settings = new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), }; 

显然,这将打印出来:

 { name: null } 

现在,我需要在JsonSerializerSettings中向ContractResolver添加另一个NullToEmptyStringResolver,如何实现以下输出:

 { name: "" } 
  • 请注意我的NullToEmptyStringResolver已经写好了。 但我需要将NullToEmptyStringResolver和CamelCasePropertyNamesContractResolver添加到Contract Resolver。

Json.Net一次不允许多个合同解析器,因此您需要一种方法来组合他们的行为。 我假设NullToEmptyStringResolver是一个自定义解析器,它inheritance自Json.Net的DefaultContractResolver类。 如果是这样,实现所需结果的一种简单方法是使NullToEmptyStringResolverinheritanceCamelCasePropertyNamesContractResolver

 public class NullToEmptyStringResolver : CamelCasePropertyNamesContractResolver { ... } 

如果你不喜欢这种方法,另一个想法是将骆驼套管行为添加到你的NullToEmptyStringResolver 。 如果你看一下如何在源代码中实现CamelCasePropertyNamesContractResolver ,你会发现这就像在构造函数中设置NamingStrategy一样简单(假设你使用的是Json.Net 9.0.1或更高版本)。 您可以将相同的代码添加到NullToEmptyStringResolver的构造函数中。

 public class NullToEmptyStringResolver : DefaultContractResolver { public NullToEmptyStringResolver() : base() { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true }; } ... } 

我发现创建复合合约解析器更好。 这是我在我的项目中使用的:

 public class CompositeContractResolver : IContractResolver, IEnumerable { private readonly IList _contractResolvers = new List(); public JsonContract ResolveContract(Type type) { return _contractResolvers .Select(x => x.ResolveContract(type)) .FirstOrDefault(Conditional.IsNotNull); } public void Add([NotNull] IContractResolver contractResolver) { if (contractResolver == null) throw new ArgumentNullException(nameof(contractResolver)); _contractResolvers.Add(contractResolver); } public IEnumerator GetEnumerator() { return _contractResolvers.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } 

然后我像这样使用它:

 Settings = new JsonSerializerSettings { ContractResolver = new CompositeContractResolver { new InterfaceContractResolver(), new DefaultContractResolver() } } 

我的自定义合约解析器返回一个null契约,因此如果没有匹配,复合契约可以通过默认契约。

 public class InterfaceContractResolver : DefaultContractResolver { public InterfaceContractResolver() { if (!typeof(T).IsInterface) throw new InvalidOperationException("T must be an interface."); } public override JsonContract ResolveContract(Type type) { return typeof(T).IsAssignableFrom(type) ? base.ResolveContract(typeof(T)) : default; } protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) { return typeof(T).IsAssignableFrom(type) ? base.CreateProperties(typeof(T), memberSerialization) : default; } } 

这是另一种选择。 您可以使用NamingStrategy而不是CamelCasePropertyNamesContractResolver ,而不是使用两个ContractResolvers。

 var settings = new JsonSerializerSettings() { ContractResolver = new NullToEmptyStringResolver(){NamingStrategy = new CamelCaseNamingStrategy()} }; 

这是类似@ BrianRogers的第二种方法。 我刚刚没有将设置硬编码为NullToEmptyStringResolver类。