虽然我按照@ZoharPeled 的建议使用 Json Schema 路径。
但正如@Todd 所建议的那样,我创建了以下解决方案,该解决方案在序列化对象时保留字段的对象类型信息。我把它放在这里只是为了参考,以防万一有人想参考它。
class TypeInfoConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var converters = serializer.Converters.Where(x => !(x is TypeInfoConverter)).ToArray();
JToken jToken = JToken.FromObject(value);
JObject jObject;
switch (jToken.Type)
{
case JTokenType.Object:
case JTokenType.Array:
case JTokenType.Bytes:
case JTokenType.Date:
jObject = JObject.FromObject(new Converter(value));
jObject.WriteTo(writer, converters);
break;
default:
//jObject = JObject.FromObject(new Converter(value));
//jObject.WriteTo(writer);
jToken.WriteTo(writer);
break;
}
}
class Converter
{
public Dictionary<string, object> _attr = new Dictionary<string, object>();
public object value;
public Converter(object value)
{
this.value = value;
addAttributes();
}
private void addAttributes()
{
Type t = value.GetType();
_attr["type"] = t.Name;
if (t.IsGenericType
&& (value is IList || value is IDictionary))
{
collectionAttributes(value, _attr, t);
}
else if (t.IsEnum)
{
_attr["type"] = "enum";
_attr["class"] = t.Name;
//attributes["meaning"] = value.ToString();
}
}
private void collectionAttributes(object value, Dictionary<string, object> attr, Type type)
{
Dictionary<string, object> o = new Dictionary<string, object>();
if (value is IDictionary && value.GetType().IsGenericType)
{
attr["type"] = "map";
attr["key"] = type.GetGenericArguments()[0].Name;
if(type.GetGenericArguments()[1].IsGenericType == true)
{
collectionAttributes(((IDictionary)value).Values, o, type.GetGenericArguments()[1]);
attr["value"] = o;
}
else
{
attr["value"] = type.GetGenericArguments()[1].Name;
}
}
else if (value is ICollection && type.IsGenericType)
{
attr["type"] = "array";
if (type.GetGenericArguments()[0].IsGenericType == true)
{
collectionAttributes(value, o, type.GetGenericArguments()[0]);
attr["value"] = o;
}
else
{
attr["of"] = type.GetGenericArguments()[0].Name;
}
}
}
}
用法
class TrialObject
{
[JsonConverter(typeof(TypeInfoConverter))]
public String szObject = "trial string";
[JsonConverter(typeof(TypeInfoConverter))]
public Double doubleObject = 999999999.999;
[JsonConverter(typeof(TypeInfoConverter))]
public Boolean boolObject = true;
[JsonConverter(typeof(TypeInfoConverter))]
public DateTime dateObject = DateTime.Now;
[JsonConverter(typeof(TypeInfoConverter))]
public GeoPoint geoPointObject = new GeoPoint() { Latitude = 123456789.123456, Longitude = 123456789.123456 };
[JsonConverter(typeof(TypeInfoConverter))]
public Dictionary<string, string> mapObject = new Dictionary<string, string>();
[JsonConverter(typeof(TypeInfoConverter))]
public Dictionary<string, List<GeoPoint>> mapObjectEx = new Dictionary<string, List<GeoPoint>>()
{{ "1", new List<GeoPoint>() { new GeoPoint() { Latitude = 0.0, Longitude = 0.0 } } }};
[JsonConverter(typeof(TypeInfoConverter))]
public List<GeoPoint> points = new List<GeoPoint>()
{ new GeoPoint() { Latitude=0.0, Longitude=0.0 } };
[JsonConverter(typeof(TypeInfoConverter))]
public Rating rating = Rating.Good;
}
class GeoPoint
{
public double Latitude;
public double Longitude;
}
enum Rating
{
Good,
Bad,
}