我有一个HashSet<string>
,JsonConvert.SerializeObject
序列化为数组。
当我使用 JsonConvert.DeserializeObject<HashSet<string>>
反序列化时,我得到了一个具有相同值的新HashSet<string>
。但是,Comparer
已重置。
// JSON settings
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
// Create a case insensitive hashset
var h = new HashSet<string>(new string[] {"A", "b"}, StringComparer.OrdinalIgnoreCase);
h.Contains("a"); // TRUE
// Serialise and deserialise with Newtonsoft.Json
string s = JsonConvert.SerializeObject(h, settings);
// s = ["A", "b"]
var newH = JsonConvert.DeserializeObject<HashSet<string>>(s, settings);
// Result is now case-sensitive
newH.Contains("a"); // FALSE
newH.Contains("A"); // TRUE
这是因为JsonConvert
使用区分大小写的EqualityComparer<string>.Default
。
如何告诉它改用StringComparer.OrdinalIgnoreCase
?
我不想在序列化数据中包含 HashSet<string>.Comparer
属性(我认为它应该是 JSON 中的简单数组),我想在反序列化时指定它。
当哈希集是根对象时,您可以使用JsonConvert.PopulateObject()
:
var newH = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
JsonConvert.PopulateObject(s, newH);
当哈希集不是根对象时,除非启用了ObjectCreationHandling.Replace
,否则 Json.NET 将填充它(如果预分配)。 这允许包含类型使用所需的比较器预先分配哈希集,例如:
public class RootObject
{
public RootObject() { this.Collection = new HashSet<string>(StringComparer.OrdinalIgnoreCase); }
public HashSet<string> Collection { get; private set; }
}
或者,您可以子类化CustomCreationConverter<HashSet<T>>
,并在转换器的Create()
方法中使用所需的比较器分配哈希集:
public class HashSetCreationConverter<T> : CustomCreationConverter<HashSet<T>>
{
public IEqualityComparer<T> Comparer { get; private set; }
public HashSetCreationConverter(IEqualityComparer<T> comparer)
{
this.Comparer = comparer;
}
public override HashSet<T> Create(Type objectType)
{
return new HashSet<T>(Comparer);
}
}
然后做:
var newH = JsonConvert.DeserializeObject<HashSet<string>>(s, new HashSetCreationConverter<string>(StringComparer.OrdinalIgnoreCase));