【问题标题】:ICollection<T> Why SerializationBinder is call on HashSet<T> but not on List<T>ICollection<T> 为什么在 HashSet<T> 上调用 SerializationBinder 而不是在 List<T> 上调用
【发布时间】:2015-11-13 00:40:29
【问题描述】:

我有一个这样的对象:

public class MyCollec
{
    public ICollection<MyObject> MyCollection { get; set; }

    public MyCollec()
    {
        MyCollection = new List<MyObject>();
    }
}

在 WebApi 中,我有一个 SerializationBinder,在我的 webApiConfig 中:

jsonFormatter.SerializerSettings.Binder = new DefaultSerializationBinder();

当我调用返回所有对象的控制器时,我得到一个这样的结构

{
  "MyCollection": [
    {
        ...
    },
    {
        ...
    }
  ]
}

但是如果我用哈希集改变我的构造函数

public MyCollec()
{
    MyCollection = new HashSet<MyObject>();
}

我的控制器的结果是这样的:

{
  "MyCollection": {
    "$type": "System.Collections.Generic.HashSet`1[[WebApplication1.Models.MyObject, WebApplication1]], System.Core",
    "$values": [
            {
                ...
            },
            {
                ...
            }
        ]
    }
}

我想知道为什么?导致这种行为的区别是什么?

是否可以使用 HashSet 但给出与列表相同的结果?

编辑:

@Grundy 评论:

TypeNameHandling 属性是 Auto 并且来自文档:包括 .NET 类型 被序列化的对象的类型不同时的名称 它声明的类型。所以似乎 HashSet 序列化与它的不一样 声明类型。

这是真的,这是原因,但为什么 List 不是真的? ICollection 的类型与 HashSet 不同...

此外,我尝试更改 TypeNameHandling 属性,但没有选项仅在继承的对象上设置 $type...

http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_TypeNameHandling.htm

【问题讨论】:

  • 我认为TypeNameHandling 属性的默认值是Auto 并且来自doc当被序列化的对象的类型与其不同时,包括.NET 类型名称声明类型。 看来HashSet 序列化与其声明的类型不同。 :-)
  • 为什么要删除自己的答案?真的解决了问题
  • 谢谢,我相信可以解决我的问题,但不能。因为如果我将 TypeNameHandling 设置为 TypeNameHandling.Objects,则在所有对象上添加一个 $type,我希望 $type 仅在我继承的对象上添加...
  • 尝试直接序列化HashSet,我不确定,但是在输出中你可以得到对象,而不是数组,当你序列化List时你总是得到数组

标签: c# serialization asp.net-web-api json.net icollection


【解决方案1】:

感谢@Grundy 提供线索。

我坚持

jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;

我有一个自定义的 JsonConverter 来更改 HashSet 的序列化

public class HashSetArrayConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        IEnumerable collectionObj = (IEnumerable)value;

        writer.WriteStartObject();

        foreach (object currObj in collectionObj)
        {
            serializer.Serialize(writer, currObj);
        }

        writer.WriteEndObject();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize(reader, objectType);
    }

    public override bool CanConvert(Type objectType)
    {
        var canConvert = IsAssignableToGenericType(objectType, typeof(HashSet<>));
        return canConvert;
    }

    private static bool IsAssignableToGenericType(Type givenType, Type genericType)
    {
        var interfaceTypes = givenType.GetInterfaces();

        if (interfaceTypes.Any(it => it.IsGenericType && it.GetGenericTypeDefinition() == genericType))
        {
            return true;
        }

        if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
            return true;

        Type baseType = givenType.BaseType;
        if (baseType == null) return false;

        return IsAssignableToGenericType(baseType, genericType);
    }
}

并将其添加到配置中:

jsonFormatter.SerializerSettings.Converters.Add(new HashSetArrayConverter());

【讨论】:

    猜你喜欢
    • 2020-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多