如何序列化 (JSON) 一个 object/class 而不是它的子项
How do I serialize (JSON) an object/class but not its children
我有:
public Class City
{
public long ID { get; set }
...
public State State { get; set; }
...
}
public Class State
{
public long ID { get; set; }
...
public Country { get; set; }
...
}
public Class Country
{
public long ID {get; set;}
...
}
在我的代码中,我序列化了一个列表<Country>
和列表<State>
,等等...
问题是,如果我序列化我的城市列表,我会得到这样的结果:
{
"ID": 3119841,
"Name": "A Coruna",
...
"State": {
"ID": 3336902,
"Name": "Galicia",
"Country": {
"ID": 2510769,
"Name": "Spain",
...
}
...
}
...
}
这会导致反序列化时出现内存和性能问题,因为具有相同国家/地区对象和状态对象等的数千个副本...我想要生成的是:
{
"ID": 3119841,
"Name": "A Coruna",
...
"StateID": 3336902,
...
}
然后我将 link 从城市到各州(我将 link 到国家等)
如果我在州和国家/地区的字段上使用忽略标志 (JsonIgnoreAttribute) 类,那么我将无法序列化它们(我认为)...
我如何实现我所追求的目标? (我目前正在使用 Json.NET,但我很乐意使用任何能够实现目标的东西。)
要从序列化中排除子结构,您可以使用 [JsonIgnore]
属性:
public class City
{
public long ID { get; set }
...
[JsonIgnore]
public State State { get; set; }
...
}
如果要扁平化结构,事情会变得更复杂。您的选择是:
- 创建一个中间扁平化结构,例如Linq 投影。
- 为您的结构创建一个自定义合同解析器,可以在这个问题中找到一个示例,可以提供一些关于如何实现此目的的灵感:How to flatten a referenced object into two json.net properties on the referer?
- 将要在
City
class 中“展平”的 State
class 的其他属性公开为属性:
public long StateID { get { return State.ID; } }
请注意,某些框架还需要您添加 [ScriptIgnore]
and/or [NonSerialized]
属性,作为 [JsonIgnore]
.[=20 的补充或替代=]
您在该字段的顶部添加 [NonSerialized] 属性。
要拥有一个普通对象(没有子对象),您可以为该对象创建一个模型并映射所需的属性。
public class City
{
public long ID { get; set }
...
[NonSerialized()]
public State State { get; set; }
...
}
要拥有一个普通对象(没有子对象),您可以为该对象创建一个模型并映射所需的属性(只有您需要的属性)。
public class CityModel
{
public long ID { get; set }
public string Name { get; set; }
...
public long StateID { get; set; }
...
}
现在我们映射 所需的属性。(这可以在您需要时可以使用的函数中)
var cityModel = new CityModel {
ID = city.ID,
Name = city.Name,
...
StateID = city.State.ID
...
}
您可以使用 JsonIgnore
忽略状态 属性 并有一个额外的 属性 称为 StateID,它从 State 对象获取其值。
public Class City
{
public long ID { get; set }
...
public int StateID
{
get
{
return State.ID;
}
}
[JsonIgnore]
public State State { get; set; }
...
}
您可以使用 [ScriptIgnore]:
public Class City
{
public long ID { get; set }
...
[ScriptIgnore]
public State State { get; set; }
...
}
我相信您最合适的解决方案如下;首先,添加所有必需的属性以拒绝对 State
对象进行序列化(您使用的设置完全取决于您使用的序列化器):
JsonIgnore
: http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonIgnoreAttribute.htm
ScriptIgnore
: https://msdn.microsoft.com/en-us/library/system.web.script.serialization.scriptignoreattribute%28v=vs.110%29.aspx
NonSerialized
(仅限字段):https://msdn.microsoft.com/en-us/library/system.nonserializedattribute%28v=vs.110%29.aspx
这样做之后,我建议你添加一个属性可以通过ID操作状态对象:
public class City
{
public long ID { get; set; }
...
[JsonIgnore, ScriptIgnore]
public State State { get; set; }
public long StateID
{
get { return State.ID; }
/* Optionally include a set; some JSON serializers may complain in
absence of it, up to you to experiment with */
set { State = new State(value); }
}
...
}
这完全保留了您的结构,State
中设计良好的构造函数可以处理接受 Id
并从中构建 State
对象。如果您不能单独从 Id
构建一个 State
对象,并且您的 JSON 序列化程序需要一个 set
变元,那么您可以简单地清空它的主体。
您也可以将其扩展到您的其他对象:
public class State
{
public long ID { get; set; }
...
[JsonIgnore, ScriptIgnore]
public Country Country { get; set; }
public long CountryId
{
get { return Country.Id; }
set { Country = new Country(value); }
}
...
}
这个模型的主要优点是,如果你做得正确并适当地设计 State
和 Country
,你的 JSON 序列化器将做 all 繁重的工作。
此外,正如 Alex 提到的,您还可以创建合同解析器,尽管这是额外的工作。
这完全取决于您的数据集。在处理大型数据集时,我只是在 属性 上使用 [JsonIgnore] 标志。从那里,我会请求城市和州异步。我会将各州放在 IEnumerable 中,然后使用 LINQ 查询来填充城市的 IEnumerable。
像这样:
Cities.ToList().ForEach((c) =>
{
c.State= States.FirstOrDefault(x => x.Id == c.StateId);
});
此外,我倾向于使用虚拟属性来引用其他对象,例如 State。
像这样:
public class City
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public int StateId { get; set; }
[JsonIgnore]
[ForeignKey("StateId")]
public virtual State State { get; set; }
}
public class State
{
public int Id { get; set; }
public string Name { get; set; }
}
如果我有 localdb 可供使用,那么我会使用不同的解决方案。
如果数据集足够小,我只需序列化整个对象并让 JSon.Net 完成繁重的工作。
我很确定您不能将 [NonSerialized] 与自定义 class 属性 一起使用。至少,它在我这边抛出了一个错误。
我有:
public Class City
{
public long ID { get; set }
...
public State State { get; set; }
...
}
public Class State
{
public long ID { get; set; }
...
public Country { get; set; }
...
}
public Class Country
{
public long ID {get; set;}
...
}
在我的代码中,我序列化了一个列表<Country>
和列表<State>
,等等...
问题是,如果我序列化我的城市列表,我会得到这样的结果:
{
"ID": 3119841,
"Name": "A Coruna",
...
"State": {
"ID": 3336902,
"Name": "Galicia",
"Country": {
"ID": 2510769,
"Name": "Spain",
...
}
...
}
...
}
这会导致反序列化时出现内存和性能问题,因为具有相同国家/地区对象和状态对象等的数千个副本...我想要生成的是:
{
"ID": 3119841,
"Name": "A Coruna",
...
"StateID": 3336902,
...
}
然后我将 link 从城市到各州(我将 link 到国家等) 如果我在州和国家/地区的字段上使用忽略标志 (JsonIgnoreAttribute) 类,那么我将无法序列化它们(我认为)...
我如何实现我所追求的目标? (我目前正在使用 Json.NET,但我很乐意使用任何能够实现目标的东西。)
要从序列化中排除子结构,您可以使用 [JsonIgnore]
属性:
public class City
{
public long ID { get; set }
...
[JsonIgnore]
public State State { get; set; }
...
}
如果要扁平化结构,事情会变得更复杂。您的选择是:
- 创建一个中间扁平化结构,例如Linq 投影。
- 为您的结构创建一个自定义合同解析器,可以在这个问题中找到一个示例,可以提供一些关于如何实现此目的的灵感:How to flatten a referenced object into two json.net properties on the referer?
- 将要在
City
class 中“展平”的State
class 的其他属性公开为属性:
public long StateID { get { return State.ID; } }
请注意,某些框架还需要您添加 [ScriptIgnore]
and/or [NonSerialized]
属性,作为 [JsonIgnore]
.[=20 的补充或替代=]
您在该字段的顶部添加 [NonSerialized] 属性。
要拥有一个普通对象(没有子对象),您可以为该对象创建一个模型并映射所需的属性。
public class City
{
public long ID { get; set }
...
[NonSerialized()]
public State State { get; set; }
...
}
要拥有一个普通对象(没有子对象),您可以为该对象创建一个模型并映射所需的属性(只有您需要的属性)。
public class CityModel
{
public long ID { get; set }
public string Name { get; set; }
...
public long StateID { get; set; }
...
}
现在我们映射 所需的属性。(这可以在您需要时可以使用的函数中)
var cityModel = new CityModel {
ID = city.ID,
Name = city.Name,
...
StateID = city.State.ID
...
}
您可以使用 JsonIgnore
忽略状态 属性 并有一个额外的 属性 称为 StateID,它从 State 对象获取其值。
public Class City
{
public long ID { get; set }
...
public int StateID
{
get
{
return State.ID;
}
}
[JsonIgnore]
public State State { get; set; }
...
}
您可以使用 [ScriptIgnore]:
public Class City
{
public long ID { get; set }
...
[ScriptIgnore]
public State State { get; set; }
...
}
我相信您最合适的解决方案如下;首先,添加所有必需的属性以拒绝对 State
对象进行序列化(您使用的设置完全取决于您使用的序列化器):
JsonIgnore
: http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonIgnoreAttribute.htm
ScriptIgnore
: https://msdn.microsoft.com/en-us/library/system.web.script.serialization.scriptignoreattribute%28v=vs.110%29.aspx
NonSerialized
(仅限字段):https://msdn.microsoft.com/en-us/library/system.nonserializedattribute%28v=vs.110%29.aspx
这样做之后,我建议你添加一个属性可以通过ID操作状态对象:
public class City
{
public long ID { get; set; }
...
[JsonIgnore, ScriptIgnore]
public State State { get; set; }
public long StateID
{
get { return State.ID; }
/* Optionally include a set; some JSON serializers may complain in
absence of it, up to you to experiment with */
set { State = new State(value); }
}
...
}
这完全保留了您的结构,State
中设计良好的构造函数可以处理接受 Id
并从中构建 State
对象。如果您不能单独从 Id
构建一个 State
对象,并且您的 JSON 序列化程序需要一个 set
变元,那么您可以简单地清空它的主体。
您也可以将其扩展到您的其他对象:
public class State
{
public long ID { get; set; }
...
[JsonIgnore, ScriptIgnore]
public Country Country { get; set; }
public long CountryId
{
get { return Country.Id; }
set { Country = new Country(value); }
}
...
}
这个模型的主要优点是,如果你做得正确并适当地设计 State
和 Country
,你的 JSON 序列化器将做 all 繁重的工作。
此外,正如 Alex 提到的,您还可以创建合同解析器,尽管这是额外的工作。
这完全取决于您的数据集。在处理大型数据集时,我只是在 属性 上使用 [JsonIgnore] 标志。从那里,我会请求城市和州异步。我会将各州放在 IEnumerable 中,然后使用 LINQ 查询来填充城市的 IEnumerable。
像这样:
Cities.ToList().ForEach((c) =>
{
c.State= States.FirstOrDefault(x => x.Id == c.StateId);
});
此外,我倾向于使用虚拟属性来引用其他对象,例如 State。
像这样:
public class City
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public int StateId { get; set; }
[JsonIgnore]
[ForeignKey("StateId")]
public virtual State State { get; set; }
}
public class State
{
public int Id { get; set; }
public string Name { get; set; }
}
如果我有 localdb 可供使用,那么我会使用不同的解决方案。
如果数据集足够小,我只需序列化整个对象并让 JSon.Net 完成繁重的工作。
我很确定您不能将 [NonSerialized] 与自定义 class 属性 一起使用。至少,它在我这边抛出了一个错误。