【问题标题】:How to serialize an IEnumerable like a regular class?如何像普通类一样序列化 IEnumerable?
【发布时间】:2021-10-15 21:44:07
【问题描述】:

我需要将Computer类型的对象转换为json字符串并写入文件。

我面临的问题是,由于计算机为超出此问题范围的目的实现 IEnumerable 接口,序列化后生成的 json 包含我的自定义枚举器提供的那些数据,尽管我正在寻找对象的属性(例如常规类如何进行通常的序列化)。

这是它的行为方式vs我希望它的行为方式:

计算机类:

class Computer : IEnumerable
{
    public string Identifier { get; set; }
    public string TeamViewerID { get; set; }
    public string TeamViewerPassword { get; set; }
    // and other properties

    public List<CPU> CPUs { get; set; }
    public List<GPU> GPUs { get; set; }
    public List<PSU> PSUs { get; set; }
    // and other collection properties

    // This Enumerator allows me to iterate thorugh Computer's collection properties
    // CPUs, GPUs, PSUs etc. as PropertyInfo
    public IEnumerator GetEnumerator()
    {
        return new DeviceCollectionPropertyEnumerator();
    }
}

序列化

// computerInstance is of type Computer (duh)
string json = Newtonsoft.Json.JsonConvert.SerializeObject(computerInstance); 

这是我得到的 json

[
    {
        "Name": "GPUs",
        "AssemblyName": "SystemInfoCollector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
        "ClassName": "SystemInfoCollector.Models.Computer",
        "Signature": "System.Collections.Generic.List`1[SystemInfoCollector.Models.GPU] GPUs",
        "Signature2": "System.Collections.Generic.List`1[[SystemInfoCollector.Models.GPU, SystemInfoCollector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] GPUs",
        "MemberType": 16,
        "GenericArguments": null
    },
    {
        "Name": "PSUs",
        "AssemblyName": "SystemInfoCollector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
        "ClassName": "SystemInfoCollector.Models.Computer",
        "Signature": "System.Collections.Generic.List`1[SystemInfoCollector.Models.PSU] PSUs",
        "Signature2": "System.Collections.Generic.List`1[[SystemInfoCollector.Models.PSU, SystemInfoCollector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] PSUs",
        "MemberType": 16,
        "GenericArguments": null
    },

    // And the rest of collection properties of Computer type ...
    // This is the stuff that is provided by DeviceCollectionPropertyEnumerator
]

我希望看到的 json(如果我摆脱 IEnumerable 实现,我可以得到它)

{
    "Identifier": "213231",
    "TeamViewerID": null,
    "TeamViewerPassword": null,
    ...
    "CPUs": [],
    "GPUs": [],
    "PSUs": [],
    ...
}

我猜我的自定义枚举器会覆盖序列化时从计算机实例中获取属性的行为。如何克服这一点?如何像任何其他不实现IEnumerator 的常规类一样序列化这台计算机?

我使用 .NET Framework 4.7.2。

【问题讨论】:

  • 那个: IEnumerable 使Computer 成为计算机列表,这很奇怪。你确定IEnumerable 应该在那里吗?计算机有部件列表,但它本身并不是这些部件的列表
  • 实现 IEnumerable 会抛弃 JSON.NET - 尽量不要实现它。
  • 我不建议您的Computer 实现IEnumerable,因为它不是一个集合。问问自己:“计算机是非通用集合吗?”,答案是否定的。如果您真的需要遍历PC的所有组件,我要做的是公开public IEnumerable&lt;IPcComponent&gt; Components并让您的各个组件实现IPcComponent
  • 不,等等。在迭代计算机组件时,我使用IEnumerable 应用迭代器设计模式,并且在我的代码库中有几个部分,我必须仅通过组件属性(组件 = cpus、gpus 等列表)和,为此,我创建了一个自定义枚举器,它允许我像这样迭代这些属性:foreach(PropertyInfo componentCollection in computer) { // do stuff },在这里实现 IEnumerable 并没有错,问题是序列化 :)
  • 嗯,说“一台计算机是并且永远是由包含组件的属性组成的PropertyInfos 的集合”是不正确的。如果你真的非常需要PropertyInfo 的列表,那么创建一个类似public IEnumerable&lt;PropertyInfo&gt; GetComponentProperties() { ... } 的方法。因为现在,你告诉 JSON.Net 的是“这个类是一个集合,将我的内容(你通过 foreaching 我得到的)序列化为 JSON 数组”,它正在执行和(正确地)序列化PropertyInfos

标签: c# json .net serialization json.net


【解决方案1】:

JsonObjectAttribute 附加到您的计算机类型:

[JsonObject]
class Computer : IEnumerable

这将强制序列化将其序列化为对象而不是集合,从而完全忽略 IEnumerableIEnumerable&lt;T&gt;

请注意,这将完全忽略 IEnumerable 部分,因此通过该集合支持序列化的任何内容都必须被忽略,或者通过您显示的那些属性进行处理。


正如您的问题中的 cmets 已经说过的那样,将计算机作为其组件的隐式集合似乎是一个奇怪的设计。由于您已经声明它是遗留代码,您希望不要过多打扰,并且只想修复 Json.net 序列化,您可以使用该属性来规避自动集合序列化。

【讨论】:

  • 非常感谢,不胜感激!
猜你喜欢
  • 2022-12-14
  • 1970-01-01
  • 2019-02-07
  • 2020-01-17
  • 1970-01-01
  • 2021-12-10
  • 2019-05-01
  • 2010-11-18
  • 2022-06-16
相关资源
最近更新 更多