泛型的 JSON 序列化



我有一个看起来像这样的类:

public class MyData : IList<Tuple<double,double>>

这个想法是你有一个值对的列表。足够简单。但我希望它被序列化,使其看起来像一个双精度数组的数组(即double[][]),而不是元组列表。序列化时应如下所示:

[[1,1],[2,2],[3,3]]

所以我创建了一个简单的JsonConverter来做到这一点。它有一个非常简单的WriteJson方法,如下所示:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var obj = value as MyData;
double[][] dataArray = (from dp in obj._data
select new[] { dp.Item1, dp.Item2 }).ToArray();
var ser = new JsonSerializer();
ser.Serialize(writer, dataArray);
}

我用适当的属性装饰MyData

[JsonConverter(typeof(MyDataJsonConverter))]
public class MyData: IList<Tuple<double,double>>

一切正常。但是,现在我想扩展它并MyData通用:

public class MyData<S,T>: IList<Tuple<S,T>>

这就是我遇到的问题。最初,我尝试使MyDataJsonConverter也是通用的:

[JsonConverter(typeof(MyDataJsonConverter<S,T>))]
public class MyData<S,T>: IList<Tuple<S,T>>

但这是不允许的,因为您不能将泛型与属性一起使用。

所以我必须保持MyDataJsonConverter非泛型的,但我需要弄清楚如何将我的元组集合展平为一个数组(现在大概是object[][]),这样当我序列化数据时,我的数据看起来像:

[[1,2],[2,3]]

或:

[["foo":1],["bar":2]]

甚至:

[["foo":"bar"],["what":"ever"]]

关于如何处理它的任何想法?在WriteJson中,我不能再将value转换为MyData,因为我不会知道类型参数,所以在这一点上一切都几乎崩溃了。

我可以为每个类型组合创建单独的类(所以一个用于Tuple<double,double>,一个用于Tuple<string,double>等等......),但我想知道在我对它进行暴力破解之前是否有更好的方法。

好的,所以这基本上是我最终做的事情(以防其他人需要类似的东西)。我的收藏看起来像这样:

[JsonConverter(typeof(MyDataJsonConverter))]
public class MyData<S,T> : IList<Tuple<S,T>>
{
private List<Tuple<S, T>> _data;
// all the implementation of IList...
}

我的自定义转换器(现在不再嵌套在MyData中)如下所示:

internal class MyDataJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(MyData<,>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Note: this is strictly for serializing, deserializing is a whole other
// ball of wax that I don't currently need!
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var obj = value as IEnumerable<dynamic>;
object[][] dataArray = (from dp in obj
select new object[] { dp.Item1, dp.Item2 }).ToArray();
var ser = new JsonSerializer();
ser.Serialize(writer, dataArray);
}
public override bool CanRead
{
get
{
return false;
}
}
}

第一件事是使用in obj,不是将自己与类的私人成员耦合,而是将其与它公开的接口耦合。那么你遇到的唯一问题是序列化Tuple<S, T>通过具有未知STobject引用持有。您可以按如下方式执行此操作,例如:

public static Tuple<object, object> UnpackUnknownTuple(object tuple)
{
var item1Property = tuple.GetType().GetProperty("Item1");
var item2Property = tuple.GetType().GetProperty("Item2");
return Tuple.Create(
item1Property.GetValue(tuple, null), 
item2Property.GetValue(tuple, null));
}
public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
var obj = value as IEnumerable;
var tuples = obj.Cast<object>().Select(UnpackUnknownTuple);
object[][] dataArray = (from dp in tuples 
select new[] { dp.Item1, dp.Item2 }).ToArray();
var ser = new JsonSerializer();
ser.Serialize(writer, dataArray);
}

另一种可能性是转换为string而不是object但我想它会干扰某些序列化设置。 如果存在任何性能问题,可以使用列表的第一个元素缓存item1Propertyitem2Property

相关内容

  • 没有找到相关文章

最新更新