我们有一个对象列表,我们想要序列化为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”是我们的延伸,但我认为这无关紧要。
答案 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);
}
}
}