C# 在JSON.net中处理引用循环
我希望将项目集合(C# 在JSON.net中处理引用循环,c#,json,json.net,C#,Json,Json.net,我希望将项目集合(列表)序列化为JSON 这些项目有一个连接集合,它提供了从一个项目到第二个项目的连接信息。由于连接对象有一个对项的引用,它使它成为一个无限循环 我的问题是,在第二次序列化对象时,是否有办法跳过连接集合的序列化。 我尝试过从JsonConverter继承和编写自定义WriteJson()方法,但从那里我没有意识到是否应该写出数组 我也尝试过使用定制的ContractResolver,但没有很好的效果 课程 public class Item { private stat
列表
)序列化为JSON
这些项目有一个连接
集合,它提供了从一个项目
到第二个项目
的连接信息。由于连接对象有一个对项的引用,它使它成为一个无限循环
我的问题是,在第二次序列化对象时,是否有办法跳过连接集合的序列化。
我尝试过从JsonConverter
继承和编写自定义WriteJson()
方法,但从那里我没有意识到是否应该写出数组
我也尝试过使用定制的ContractResolver,但没有很好的效果
课程
public class Item
{
private static int _lastID = 0;
public Item()
{
ID = ++_lastID;
Connections = new List<Connection>();
}
public int ID { get; set; }
public string Name { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public List<Connection> Connections { get; set; }
}
public class Connection
{
private Connection(ConnectionType type, Item source, Item target)
{
if (type == ConnectionType.None)
throw new ArgumentException();
if (source == null)
throw new ArgumentNullException("source");
if (target == null)
throw new ArgumentNullException("target");
Type = type;
Source = source;
Target = target;
}
public ConnectionType Type { get; set; }
public Item Source { get; set; }
public Item Target { get; set; }
public static void Connect(ConnectionType type, Item source, Item target)
{
var conn = new Connection(type, source, target);
source.Connections.Add(conn);
target.Connections.Add(conn);
}
}
编辑:
[
{
"id": 1,
"name": "Item #1",
"prop1": "val1",
"prop2": "val2",
"connections": {
"type": "ConnType",
"source": {
"id": 1,
"name": "Item #1",
"prop1": "val1",
"prop2": "val2"
// no connections array
},
"target": {
"id": 2,
"name": "Item #2",
"prop1": "val1",
"prop2": "val2"
// no connections array
}
}
},
{
"id": 2,
"name": "Item #2",
"prop1": "val1",
"prop2": "val2",
"connections": {
"type": "ConnType",
"source": {
"id": 1,
"name": "Item #1",
"prop1": "val1",
"prop2": "val2"
// no connections array
},
"target": {
"id": 2,
"name": "Item #2",
"prop1": "val1",
"prop2": "val2"
// no connections array
}
}
}
]
C#
有一个问题,因为Json中不能引用对象(请参阅) 这意味着每次引用中出现一个项目时,您都必须复制该项目,以便将所有连接带到客户端 我建议只使用ID将连接带到客户端,并将连接作为一个单独的对象 将
JsonIgnore
属性添加到项上的Connections
属性中
[JsonIgnore]
public List<Connection> Connections { get; set; }
[JsonIgnore]
公共列表连接{get;set;}
并使用类来发送到客户端,而不是直接发送项目列表
class ConnectionContainer
{
private readonly List<Item> _items;
private readonly List<ConnectionInfo> _connections;
public ConnectionContainer(IEnumerable<Item> items)
{
_items = items.ToList();
Connections = items.SelectMany(i => i.Connections).Distinct().Select(c => new ConnectionInfo
{
Type = c.Type,
SourceId = c.Source.ID,
TargetId = c.Target.ID
}).ToList();
}
public List<Item> Items
{
get { return _items; }
}
public List<ConnectionInfo> Connections
{
get { return _connections; }
}
}
class ConnectionInfo
{
private ConnectionType Type { get; set; }
private int SourceId { get; set; }
private int TargetId { get; set; }
}
类连接容器
{
私有只读列表项;
专用只读列表\u连接;
公共连接容器(IEnumerable items)
{
_items=items.ToList();
Connections=items.SelectMany(i=>i.Connections).Distinct().Select(c=>newconnectioninfo
{
类型=c.类型,
SourceId=c.Source.ID,
TargetId=c.Target.ID
}).ToList();
}
公共清单项目
{
获取{return\u items;}
}
公共列表连接
{
获取{return\u connections;}
}
}
类连接信息
{
私有连接类型类型{get;set;}
private int SourceId{get;set;}
私有int TargetId{get;set;}
}
您可以引入一个新类,例如,ItemClass
,该类将包含classItem
的所有字段,但Connections
属性除外,而不是从Item
开始声明源
和目标
的类型
public class ItemClass
{
public int ID { get; set; }
public string Name { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
public class Connection
{
// ...
public ConnectionType Type { get; set; }
public ItemClass Source { get; set; }
public ItemClass Target { get; set; }
// ...
}
现在,您将有相应地填充新的ItemClass
类型实例的开销。将其添加到Global.asax(或在WebApiConfig或任何其他配置类中)
var jsonFormatter=config.Formatters.OfType().First();
jsonFormatter.SerializerSettings.ReferenceLoopHandling=ReferenceLoopHandling.Ignore;
如果我没弄错,您只需要保留包含连接集合的第一个引用深度?如果是这种情况,请尝试使用:
settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
settings.MaxDepth = 1;
如果我使用这个属性,我会丢失所有连接信息,我更希望它只包含第一个对象的信息,因为这些类在一个单独的项目中,我希望避免引用Newtonsoft。如果我以前尝试过混用ReferenceLoopHandling
,但运气不好,但现在当我再次尝试时,它给了我我想要的。谢谢你给我指出了正确的方向。尽管我使用了JsonConvert.SerializeObject(集合、设置)
现在我想起了为什么它不能与ReferenceLoopHandling.Ignore
一起工作。连接对象只有一个引用(源引用或目标引用),这取决于它是从哪个对象序列化的。这对我来说不起作用,所以我会在allI喜欢这个解决方案之后使用@Wasif的解决方案,但由于它引入了更多的复杂性,我使用@Moeri解决方案
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
settings.MaxDepth = 1;