【问题标题】:Json.NET: how to remove assembly info from types in the resulting json string?Json.NET:如何从生成的 json 字符串中的类型中删除程序集信息?
【发布时间】:2017-11-28 15:35:53
【问题描述】:

我正在使用 Json.NET 进行序列化,但结果字符串太长了,因为它包含大量关于我没有用的程序集的多余信息。

例如,这是我得到的其中一种类型:

"Assets.Logic.CompGroundType, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null": {
"$type": "Assets.Logic.CompGroundType, Assembly-CSharp",
"GroundType": 1,
"EntityID": 1,
"<GroundType>k__BackingField": 1
}

“GroundType”是一个枚举,“EntityID”是一个整数。

这是我想要的结果:

"Assets.Logic.CompGroundType" : {
"$type": "Assets.Logic.CompGroundType",
"GroundType": 1,
"EntityID": 1,
"<GroundType>k__BackingField": 1
}

如果可能的话,我还想删除“$type”字段,同时仍然正确反序列化继承的类型(我不确定为什么有必要,因为该信息是从上面的一行复制的,但如果我删除它通过设置 TypeNameHandling.None,我得到子类型的反序列化错误)。我也不确定最后一个字段 (k__BackingField) 的用途。

如果可能的话,我想进一步减少它,以:

"Assets.Logic.CompGroundType" : {
"GroundType": 1,
"EntityID": 1,
}

我知道可以为 Json.Net 中的每种类型手动自定义序列化方案,但我有数百种类型,所以我想通过一些全局设置自动完成。

我尝试更改“FormatterAssemblyStyle”,但那里没有“None”选项,只有“Simple”或“Full”,而且我已经在使用“Simple”了。

提前感谢您的帮助。

编辑:

请务必注意,类型是字典中的键。这就是该类型出现两次的原因(在第一个示例的第一行和第二行中)。

实现自定义 SerializationBinder 后,我能够减少“$type”字段的长度,但不能减少 Dictionary 键字段的长度。现在我得到以下信息:

"componentDict": {
      "Assets.Logic.CompGroundType, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null": {
        "$type": "Assets.Logic.CompGroundType",
        "GroundType": 1,
        "EntityID": 1,
        "<GroundType>k__BackingField": 1
      }
    }

编辑 2:

我要序列化的代码是entity component system。我将尝试提供带有代码示例的详细示例。

所有组件(包括上面的CompGroundType)都继承自以下抽象类:

abstract class Component
{
    public int EntityID { get; private set; }
    protected Component(int EntityID)
    {
        this.EntityID = EntityID;
    }
}

我遇到的问题是Entity类的序列化componentDict

class Entity
{
    readonly public int id;

    private Dictionary<Type, Component> componentDict = new Dictionary<Type, Component>();

    [JsonConstructor]
    private Entity(Dictionary<Type, Component> componentDict, int id)
    {
        this.id = id;
        this.componentDict = componentDict;
    }
}

componentDict 包含附加到实体的所有组件。在每个条目&lt;Type, Component&gt;中,值的类型等于键。

我正在递归地进行序列化,使用以下JsonSerializerSettings

JsonSerializerSettings serializerSettings = new JsonSerializerSettings()
{
     ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
     ContractResolver = new MyContractResolver(),
     TypeNameHandling = TypeNameHandling.Auto,
     SerializationBinder = new TypesWithNoAssmeblyInfoBinder(),
     Formatting = Formatting.Indented
}

其中MyContractResolverthis answer 的一种形式相同。

TypesWithNoAssmeblyInfoBinder 从编辑 1 中进行更改:

private class TypesWithNoAssmeblyInfoBinder : ISerializationBinder
        {
            public Type BindToType(string assemblyName, string typeName)
            {
                return Type.GetType(typeName);
            }

            public void BindToName(Type serializedType, out string assemblyName, out string typeName)
            {
                assemblyName = null;
                typeName = serializedType.FullName;
            }
        }

序列化本身是这样完成的:

            var jsonSerializer = JsonSerializer.Create(serializerSettings);

            using (FileStream zippedFile = new FileStream(Application.persistentDataPath + fileName, FileMode.Create))
            {
                using (GZipStream archive = new GZipStream(zippedFile, CompressionLevel.Fastest))
                {
                    using (StreamWriter sw = new StreamWriter(archive))
                    {
                        jsonSerializer.Serialize(sw, savedData);
                    }
                }
            }

编辑 4:

CompGroundType 类(已完成组件的示例):

class CompGroundType : Component
{
    public enum Type {Grass, Rock};

    public Type GroundType { get; private set; }

    [JsonConstructor]
    private CompGroundType(Type groundType, int entityID) : base(entityID)
    {
        this.GroundType = groundType;
    }
}

【问题讨论】:

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


【解决方案1】:

第一部分是嵌入的 $type 信息,由 json.net 注入,以帮助稍后进行反序列化。我认为文档中的this example 会做你想做的事。

public class KnownTypesBinder : ISerializationBinder
{
    public IList<Type> KnownTypes { get; set; }

    public Type BindToType(string assemblyName, string typeName)
    {
        return KnownTypes.SingleOrDefault(t => t.Name == typeName);
    }

    public void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        assemblyName = null;
        typeName = serializedType.Name;
    }
}

public class Car
{
    public string Maker { get; set; }
    public string Model { get; set; }
}

KnownTypesBinder knownTypesBinder = new KnownTypesBinder
{
    KnownTypes = new List<Type> { typeof(Car) }
};

Car car = new Car
{
    Maker = "Ford",
    Model = "Explorer"
};

string json = JsonConvert.SerializeObject(car, Formatting.Indented, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects,
    SerializationBinder = knownTypesBinder
});

Console.WriteLine(json);
// {
//   "$type": "Car",
//   "Maker": "Ford",
//   "Model": "Explorer"
// }

object newValue = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects,
    SerializationBinder = knownTypesBinder
});

Console.WriteLine(newValue.GetType().Name);
// Car

它只需要根据您的特定需求进行调整。

那么第二部分是字典键,它来自被序列化的Type对象。

我认为您可以通过 creating a custom JsonConverter 自定义它,但事实证明字典键具有“特殊”处理,这意味着更复杂的解决方法。抱歉,我没有更复杂的解决方法的示例。

【讨论】:

  • 这看起来正是我所需要的。我实现了它,但不幸的是我正在为 Unity 编写它,结果发现 Json.NET unity fork 有 a bug where setting a custom Binder is useless,因为它的函数从未被调用...
  • 好的,我设法解决了这个问题并使用了完整的 Json.NET 库,而不是 Unity 分支,但即使在实现了上述示例之后,我也得到了以下信息:"componentDict": { "Assets.Logic.CompGroundType, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null": { "$type": "Assets.Logic.CompGroundType", "GroundType": 1, "EntityID": 1, "&lt;GroundType&gt;k__BackingField": 1 } } 所以就像你可以看,“$type”字段只包含名称,但字典键仍然包含程序集。
  • 字典键中的程序集名称来自 Type 对象的序列化。我已经更新了答案以涵盖基于类型的对象的自定义序列化。
  • 我刚刚查看了我添加的额外信息,这是错误的,对此感到抱歉。我已经编辑了我的答案以反映这一点。
  • (我现在才看到你的最后一次编辑)结果字典键没有使用 JsonConverter 序列化。如this answer 中所述,我必须为整个字典编写一个自定义的 JsonConverter。这也意味着我最终甚至不需要自定义活页夹。无论如何,感谢您指出最终将我引向正确方向的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
  • 2019-03-02
相关资源
最近更新 更多