如何序列化 (JSON) 对象/类而不是其子对象/类



我有:

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,
...
}

然后我将城市与各州联系起来(我将与国家等联系起来) 如果我在州和国家/地区类中的字段上使用忽略标志 (JsonIgnoreAttribute),那么我将无法序列化它们(我认为)...

我如何实现我所追求的?(我目前正在使用 Json.NET,但很乐意使用任何可以实现目标的东西。

若要从序列化中排除子结构,可以使用[JsonIgnore]属性:

public class City
{
public long ID { get; set }
...
[JsonIgnore]
public State State { get; set; }
...
}

如果你想扁平化结构,事情会变得更加复杂。您的选择是:

  1. 创建一个中间扁平结构,例如 Linq 投影的结果。
  2. 为您的结构创建自定义协定解析器,可以在以下问题中找到有关如何实现此目的的一些灵感的示例:如何将引用的对象展平为引用器上的两个 json.net 属性?
  3. 要在City类中"平展"的State类的其他属性公开为属性:
public long StateID { get { return State.ID; } }

请注意,某些框架还要求您添加[ScriptIgnore]和/或[NonSerialized]属性,以及作为[JsonIgnore]的替代属性。

在该字段的顶部添加 [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

忽略 State 属性,并拥有一个名为 StateID 的附加属性,该属性从 State 对象获取其值。

public Class City
{
public long ID { get; set }
...
public int StateID 
{
get
{
return State.ID;
}
}
[JsonIgnore]
public State State { get; set; }
...
}

我相信你最合适的解决方案是这样的;首先,添加所有必需的属性来拒绝对State对象的序列化(你使用哪个集合完全取决于你使用的Serailizer):

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); }
}
...
}

此模型的主要优点是,如果正确执行并正确设计StateCountry,则 JSON 序列化程序将完成所有繁重的工作。

此外,正如 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; }
}

如果我有一个本地数据库可供我使用,那么我会使用不同的解决方案。

如果它是一个足够小的数据集,我只需序列化整个对象,JSon.Net 做繁重的工作。

我很确定您不能将 [非序列化] 与自定义类属性一起使用。至少,它在我的方面抛出了一个错误。

您可以使用 [ScriptIgnore]:

public Class City
{
public long ID { get; set }
...
[ScriptIgnore]
public State State { get; set; }
...
}

相关内容

  • 没有找到相关文章

最新更新