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

时间:2015-04-30 19:42:17

标签: c# json serialization json.net

我有:

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

然后我将城市连接到各州(我将链接到该国家等) 如果我在州和国家类的字段上使用Ignore标志(JsonIgnoreAttribute),那么我将无法对它们进行序列化(我认为)......

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

6 个答案:

答案 0 :(得分:3)

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

't_RB

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

  1. 创建一个中间扁平结构,作为例如Linq投影。
  2. 为您的结构创建自定义合约解析程序,可以在此问题中找到可能提供如何实现此目标的一些示例:How to flatten a referenced object into two json.net properties on the referer?
  3. 公开您想要的public class City { public long ID { get; set } ... [JsonIgnore] public State State { get; set; } ... } 课程的其他属性&#34;展平&#34;在State类中作为属性:
  4.     public long StateID { get { return State.ID; } }

    请注意,除City之外或作为[ScriptIgnore]的替代方案,某些框架还需要您添加[NonSerialized]和/或[JsonIgnore]属性。

答案 1 :(得分:2)

您可以在该字段的顶部添加[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
    ...
}

答案 2 :(得分:1)

您可以使用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; }
    ...
}

答案 3 :(得分:0)

我相信你最合适的解决方案如下;首先,添加所有必需的属性以拒绝State对象上的序列化(您使用的设置完全取决于您使用的选择器):

JsonIgnorehttp://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonIgnoreAttribute.htm

ScriptIgnorehttps://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对象。如果你不能单独从State构建一个Id对象,并且你的JSON Serializer需要一个set mutator,那么你可以简单地清空它的主体。

您也可以将其展开到其他对象:

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 Serializer将执行 all 繁重的工作。< / p>

另外,正如Alex提到的那样,你也可以创建合同解析器,尽管这是额外的工作。

答案 4 :(得分:0)

这完全取决于您的数据集。处理大型数据集时,我只需在属性上使用[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]与自定义类属性一起使用。至少,它在我身上犯了一个错误。如果有人可以提供关于如何做到这一点的Json示例,我想学习一些新东西。

希望这有帮助! 〜干杯

答案 5 :(得分:-1)

您可以使用[ScriptIgnore]:

public Class City
{
    public long ID { get; set }
    ...

    [ScriptIgnore]
    public State State { get; set; }
    ...
}