我有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中的一个简单数组),我想在反序列化时指定它。
答案 0 :(得分:2)
当哈希集是根对象时,您可以使用JsonConvert.PopulateObject()
:
var newH = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
JsonConvert.PopulateObject(s, newH);
当哈希集不根对象时,如果预分配,Json.NET将填充它,除非启用ObjectCreationHandling.Replace
。这允许包含类型使用所需的比较器预分配哈希集,例如:
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));