C# JSON.NET序列化-DefaultReferenceResolver如何比较相等性?
我使用的是JSON.NET6.0.3。我已将C# JSON.NET序列化-DefaultReferenceResolver如何比较相等性?,c#,asp.net-web-api,json.net,C#,Asp.net Web Api,Json.net,我使用的是JSON.NET6.0.3。我已将preserverences选项更改如下: HttpConfiguration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects; 我的对象图类似于以下内容: public class CarFromManufacturer { public int CarID { get; s
preserverences
选项更改如下:
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; }
}
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();
}
}
我的WebAPI控制器正在返回IEnumerable[CarFromManufacturer]
的结果集。因此,结果可能是来自两个独特制造商对象的5辆汽车的列表。我希望JSON结果只列出一次完全序列化的每个制造商,然后同一制造商的后续使用是$ref ID到原始的$ID。这是不可能的
尽管我找不到一篇文档来说明如何为referencesolver建立平等性,但我已经实现了IEquatable
,以及base.Equals
和base.GetHashCode()
的覆盖,但运气不好
我希望避免实现我自己的,因为在同一个项目中有非常相似的对象图
我能想到的唯一一件事是,我正在使用factory对象,而不是先创建每个唯一的CarManufacturer
,然后创建CarFromManufacturer
的实例,传入CarManufacturer
。。。我正在创建CarManufacturer
的新实例。这可以解释为什么对象不相等,但这就是为什么我实现了IEquatable
和重写base.Equals(object)
和base.GetHashCode()
我已经研究了,它使用了,它使用了
EqualityComparer
。默认值,从中,使用T的IEquatable
实现(如果存在),或者使用T的base.Equals()
实现。。。。所有这些都让我相信CarManufacturer
中的IEquatable
应该可以解决我的问题。但是,在CarManufacturer.Equals()
和GethashCode()
中放置断点时,默认情况下JSON.NET解析引用的逻辑只会使用
如果要以不同的方式比较对象,则必须实现自定义的IReferenceResolver
下面是一个采用IEqualityComparer
来适应您的用例的示例:
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;
}
}
公共类referencesolver:IReferenceResolver
{
私有字典字符串引用;
私用词典引用;
私人国际参考计数;
公共引用解算器(IEqualityComparer比较器)
{
this.stringToReference=新字典();
this.referenceToString=新字典(比较器);
this.referenceCount=0;
}
公共无效添加引用(
对象上下文,
字符串引用,
对象值)
{
这个.referenceToString.Add((T)值,reference);
此.stringToReference.Add(参考,(T)值);
}
公共字符串GetReference(
对象上下文,
对象值)
{
字符串结果=null;
如果(!this.referenceToString.TryGetValue((T)值,输出结果))
{
referenceCount++;
结果=referenceCount.ToString(CultureInfo.InvariantCulture);
this.referenceToString.Add((T)值,结果);
this.stringToReference.Add(结果,(T)值);
}
返回结果;
}
公共布尔是参考的(
对象上下文,
对象值)
{
返回此.referenceToString.ContainsKey((T)值);
}
公共对象解析引用(
对象上下文,
字符串引用)
{
tr=默认值(T);
this.stringToReference.TryGetValue(参考,out r);
返回r;
}
}
Json.Net将对被比较的对象调用Equals方法。在某些情况下,您可能不希望这样做,但是,例如,当它检查循环引用时,它也会这样做,而检查引用是否相等可能更理想。然而,他们这样做是为了通过重写类中的Equals方法来给予开发人员完全的控制权
您可以覆盖默认实现。例如,要使其成为引用等式,您可以执行以下操作:
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; }
}
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();
}
}
我每次创建Manufacturer的新实例的原因是因为我的factory对象接受联接表记录的EF实体(联接car和Manufacturer)。。因此,它从EF car对象构建汽车,并调用带有EF Manufacturer的ManufacturerFactory。看起来对象引用进行了相等性比较。实现
IReferenceResolver
有什么问题吗?谢谢你的想法!重写Equals和GetHashCode是否不足以让JSON.NET的DefaultReferenceSolver知道如何比较对象?实现IReferenceResolver没有什么错,只是如果没有这个问题,我不需要额外的复杂性。。在这样做之前,我宁愿重新构造工厂代码。但问题是DefaultReferenceSolver如何比较平等。我正在更新帖子。通过查看源代码,我相信它默认使用,它只比较有关更新的引用:defaultreferencesolver
calls。这个方法使用了我上面提到的比较器,并且没有使用BidirectionalDictionary
的默认构造函数。非常感谢!理想情况下,可以在HttpConfiguration.Formatters.JsonFormatter.SerializerSettings.ReferenceResolver全局应用解析器,并使用依赖项解析。我将大胆地假设所有将被序列化的模型对象都是不可变的,因此对于序列化而言,引用平等性并不重要。谢谢如果你有任何见解。。。这里也讨论了这一点: