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

时间:2017-01-26 13:58:25

标签: json.net

我有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中的一个简单数组),我想在反序列化时指定它。

1 个答案:

答案 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));