我正在使用JSON.NET 6.0.3。我更改了PreserveReferences选项,如下所示:
HttpConfiguration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
我的对象图类似于以下内容:
public class CarFromManufacturer
{
public int CarID { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public CarManufacturer Manufacturer { get; set; }
}
public class CarManufacturer
{
public int ManufacturerID { get; set; }
public string Name { get; set; }
}
我的WebAPI控制器正在返回IEnumerable [CarFromManufacturer]的结果集。因此,结果可能是来自两个独特制造商对象的5辆汽车的列表。我希望JSON结果只列出每个制造商一次完全序列化,然后将同一制造商的后续使用作为$ ref ID到原始的$ id。那种情况没有发生。
即使我找不到单一文档来说明如何为ReferenceResolver建立相等性,我已经实现了IEquatable以及base.Equals和base.GetHashCode()的覆盖,但没有运气。
我希望避免实现我自己的IReferenceResolver,因为在同一个项目中有非常相似的对象图按预期工作。
我唯一能想到的是我正在使用工厂对象,而不是先创建每个独特的CarManufacturer,然后创建CarFufacturer中传递的CarFromManufacturer实例...我正在创建CarManufacturer的新实例。这可以解释为什么对象不相等,但这就是我实现IEquatable并覆盖base.Equals(object)和base.GetHashCode()的原因。
我查看了source for DefaultReferenceResolver并使用了使用EqualityComparer.Default的default constructor of BidirectionalDictionary,它来自MSDN documentation,使用了Tqu的IEquatable实现它存在,或以其他方式使用T的base.Equals()实现......所有这些都会让我相信CarManufacturer中的IEquatable应该解决我的问题。但是,在CarManufacturer.Equals()和GethashCode()中放置断点永远不会命中..
答案 0 :(得分:3)
JSON.NET默认解析引用的逻辑只是使用this comparer来比较引用。
如果您想以不同的方式比较对象,则必须实现自定义IReferenceResolver
。
以下是一个使用IEqualityComparer<T>
来满足您的用例的示例:
public class ReferenceResolver<T> : IReferenceResolver
{
private Dictionary<string, T> stringToReference;
private Dictionary<T, string> referenceToString;
private int referenceCount;
public ReferenceResolver(IEqualityComparer<T> comparer)
{
this.stringToReference = new Dictionary<string, T>();
this.referenceToString = new Dictionary<T, string>(comparer);
this.referenceCount = 0;
}
public void AddReference(
object context,
string reference,
object value)
{
this.referenceToString.Add((T)value, reference);
this.stringToReference.Add(reference, (T)value);
}
public string GetReference(
object context,
object value)
{
string result = null;
if (!this.referenceToString.TryGetValue((T)value, out result))
{
referenceCount++;
result = referenceCount.ToString(CultureInfo.InvariantCulture);
this.referenceToString.Add((T)value, result);
this.stringToReference.Add(result, (T)value);
}
return result;
}
public bool IsReferenced(
object context,
object value)
{
return this.referenceToString.ContainsKey((T)value);
}
public object ResolveReference(
object context,
string reference)
{
T r = default(T);
this.stringToReference.TryGetValue(reference, out r);
return r;
}
}
答案 1 :(得分:1)
Json.Net将在被比较的对象上调用Equals方法。在某些情况下,您可能不希望这样,例如,当它检查循环引用时,它会执行相同的操作,而检查引用相等性可能更为理想。但是,他们这样做是为了通过覆盖类中的Equals方法来让开发人员完全控制。
您可以覆盖默认实现。例如,为了使它成为引用相等,您将执行以下操作:
var settings = new JsonSerializerSettings
{
EqualityComparer = new DefaultEqualityComparer(),
};
public class DefaultEqualityComparer : IEqualityComparer
{
public bool Equals(object x, object y)
{
return ReferenceEquals(x, y);
}
public int GetHashCode(object obj)
{
return obj.GetHashCode();
}
}