JSON.net将无类型列表序列化为类型列表?

时间:2015-04-13 11:23:22

标签: c# json serialization

我们有一个对象列表,我们想要序列化为json字符串。 这些对象各有一个Property,它是一个无类型的ICollection。 问题是,我们希望反序列化JSON并将其与另一个列表进行比较,并且在序列化时,我们有信息,它的类型是。

由于我们无法将属性更改为类型列表,是否可以告诉JSON.NET:“它是无类型的,但序列化它就像键入T类型一样?”

我猜,我可能会在反序列化和kindahow传递类型时抛出它,但这会非常混乱。

编辑:我现在通过将数据从JSON转换为预期类型来使用凌乱的方式:

    private static void CastAssertDataSources(ReportDataSource dataSourceFromDb, ReportDataSource dataSourceFromJson)
    {
        var dtoType = dataSourceFromDb.Data.GetType().GetElementType();

        var dtosFromJson = new ArrayList(dataSourceFromJson.Data);
        ArrayList typedJsonDtos = new ArrayList();

        for (int i = 0; i < dataSourceFromJson.Data.Count; i++)
        {
            var jsonDto = dtosFromJson[i];
            var containerJsonDto = (JContainer)jsonDto;
            var typedJsonDto = containerJsonDto.ToObject(dtoType);
            typedJsonDtos.Add(typedJsonDto);
        }

        dataSourceFromJson = new ReportDataSource(dataSourceFromJson.Name, typedJsonDtos);
        dataSourceFromDb.AssertIsEqualTo(dataSourceFromJson);
    }

“AssertisEqualTo”是我们的延伸,但我认为这无关紧要。

1 个答案:

答案 0 :(得分:1)

假设你的班级看起来像这样:

public class ReportDataSource 
{
    public string Name { get; set; }
    public ICollection Data { get; set; }
}

您可以使用适当的JsonConverter

来执行此操作
public sealed class TypedToTypelessCollectionConverter : JsonConverter
{
    [ThreadStatic]
    static Type itemType;

    public static IDisposable SetItemType(Type deserializedType)
    {
        return new ItemType(deserializedType);
    }

    sealed class ItemType : IDisposable
    {
        Type oldType;

        internal ItemType(Type type)
        {
            this.oldType = itemType;
            itemType = type;
        }

        int disposed = 0;

        public void Dispose()
        {
            // Dispose of unmanaged resources.
            if (Interlocked.Exchange(ref disposed, 1) == 0)
            {
                // Free any other managed objects here.
                itemType = oldType;
                oldType = null;
            }
            // Suppress finalization.  Since this class actually has no finalizer, this does nothing.
            GC.SuppressFinalize(this);
        }
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(ICollection);
    }

    public override bool CanWrite { get { return false; }}

    public override bool CanRead { get { return itemType != null; } }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize(reader, typeof(List<>).MakeGenericType(itemType));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public static class TypeExtensions
{
    /// <summary>
    /// Return all interfaces implemented by the incoming type as well as the type itself if it is an interface.
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public static IEnumerable<Type> GetInterfacesAndSelf(this Type type)
    {
        if (type == null)
            throw new ArgumentNullException();
        if (type.IsInterface)
            return new[] { type }.Concat(type.GetInterfaces());
        else
            return type.GetInterfaces();
    }

    public static IEnumerable<Type> GetEnumerableTypes(this Type type)
    {
        foreach (Type intType in type.GetInterfacesAndSelf())
        {
            if (intType.IsGenericType
                && intType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
            {
                yield return intType.GetGenericArguments()[0];
            }
        }
    }
}

然后使用它:

public class ReportDataSource 
{
    public string Name { get; set; }

    [JsonConverter(typeof(TypedToTypelessCollectionConverter))]
    public ICollection Data { get; set; }

    public static ReportDataSource Deserialize(ReportDataSource dataSourceFromDb, string json)
    {
        using (TypedToTypelessCollectionConverter.SetItemType(dataSourceFromDb == null || dataSourceFromDb.Data == null ? null : dataSourceFromDb.Data.GetType().GetEnumerableTypes().SingleOrDefault()))
        {
            return JsonConvert.DeserializeObject<ReportDataSource>(json);
        }
    }
}