将 Newtonsoft.Json.JsonConvert 的比较器设置为用于 HashSet/Dictionary



我有一个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));

相关内容

  • 没有找到相关文章

最新更新