在Newtonsoft.Json中添加多个契约解析器
本文关键字:契约 Newtonsoft Json 添加 | 更新日期: 2023-09-27 18:07:58
数据结构蓝图:
public class Movie
{
public string Name { get; set; }
}
使用Newtonsoft 。Json,我对Json序列化有以下配置:
var settings = new JsonSerializerSettings() {
ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
很明显,这将打印出:
{
name: null
}
现在,我需要添加另一个NullToEmptyStringResolver到JsonSerializerSettings中的ContractResolver,我如何才能实现输出如下:
{
name: ""
}
- 请注意我的NullToEmptyStringResolver已经写好了。但是我需要添加两个NullToEmptyStringResolver和CamelCasePropertyNamesContractResolver到合同解析器。
Json。Net不允许同时使用多个契约解析器,因此您需要一种方法来组合它们的行为。我假设NullToEmptyStringResolver
是一个自定义解析器,继承自Json。Net的DefaultContractResolver
类。如果是这样,实现预期结果的一个简单方法是使NullToEmptyStringResolver
继承自CamelCasePropertyNamesContractResolver
。
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<IContractResolver>
{
private readonly IList<IContractResolver> _contractResolvers = new List<IContractResolver>();
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<IContractResolver> GetEnumerator()
{
return _contractResolvers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
然后我这样使用它:
Settings = new JsonSerializerSettings
{
ContractResolver = new CompositeContractResolver
{
new InterfaceContractResolver<ISomething>(),
new DefaultContractResolver()
}
}
我的自定义合约解析器返回一个null
合约,因此如果没有匹配,复合合约可以通过默认合约。
public class InterfaceContractResolver<T> : 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<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
return
typeof(T).IsAssignableFrom(type)
? base.CreateProperties(typeof(T), memberSerialization)
: default;
}
}
这是另一种选择。比起使用两个合约解析器,您可以使用NamingStrategy
而不是CamelCasePropertyNamesContractResolver
。
var settings = new JsonSerializerSettings()
{
ContractResolver = new NullToEmptyStringResolver(){NamingStrategy = new CamelCaseNamingStrategy()}
};
这是类似的@BrianRogers的第二种方法。我只是没有硬编码设置为NullToEmptyStringResolver
类。