ICollection< T>为什么SerializationBinder调用HashSet<但不在名单上

本文关键字:名单 HashSet 调用 为什么 SerializationBinder ICollection | 更新日期: 2023-09-27 18:08:50

我有一个像这样的对象:

public class MyCollec
{
    public ICollection<MyObject> MyCollection { get; set; }
    public MyCollec()
    {
        MyCollection = new List<MyObject>();
    }
}

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

jsonFormatter.SerializerSettings.Binder = new DefaultSerializationBinder();

当我调用返回all对象的控制器时我得到了这样的结构

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

但是如果我用hashset

改变构造函数
public MyCollec()
{
    MyCollection = new HashSet<MyObject>();
}
我的控制器的结果是这样的:
{
  "MyCollection": {
    "$type": "System.Collections.Generic.HashSet`1[[WebApplication1.Models.MyObject, WebApplication1]], System.Core",
    "$values": [
            {
                ...
            },
            {
                ...
            }
        ]
    }
}

我想知道为什么?是什么差异导致了这种行为?

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

编辑:

@Grundy comment:

TypeNameHandling属性是Auto和from doc:包括。net类型当被序列化的对象的类型与它声明的类型。看来序列化的HashSet和它的不一样声明类型。

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

此外,我试图改变TypeNameHandling属性,但没有选项设置$type仅对继承对象…

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

ICollection< T>为什么SerializationBinder调用HashSet<但不在名单上

感谢@Grundy的提示。

I keep

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

并添加到config:

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