【问题标题】:JSON.net serializing untyped list as typed list?JSON.net 将无类型列表序列化为类型列表?
【发布时间】:2015-04-13 11:23:22
【问题描述】:

我们有一个对象列表,我们想将其序列化为 json 字符串。 这些对象每个都有一个属性,它是一个无类型的 ICollection。 问题是,我们想反序列化 JSON 并将其与另一个列表进行比较,并且在序列化时,我们得到了信息,它是哪种类型。

由于我们不能将属性更改为类型化列表,是否有可能告诉 JSON.NET:“它是非类型化的,但将其序列化,就像它是类型 T 的类型一样?”

我想,在反序列化并以某种方式传递类型时,我可能会强制转换它,但这会很混乱。

编辑:我现在通过将数据从 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”是我们的扩展,但我猜这应该没关系。

【问题讨论】:

  • 在序列化无类型集合时,您能否显示当前正在创建的 JSON,以及您想要创建的 JSON?目前,当 Json.Net 序列化 ArrayList 时,它只是序列化发生的任何事情。
  • 是的,序列化不是问题,但是当我反序列化 JSON 时,我得到的只是一个“Jcontainer”对象数组。查看我的编辑

标签: c# json serialization


【解决方案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);
        }
    }
}

【讨论】:

  • 嗯,这是一个答案。我会尽快试一试。到目前为止,谢谢,如果可以的话,我会投票两次
猜你喜欢
  • 1970-01-01
  • 2021-04-05
  • 2012-12-09
  • 1970-01-01
  • 2012-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多