我正在编写一个实用程序,它读取一个文本文件(json)并动态构建一个json对象并将其发送到REST API。为了实现这一点,我希望我的序列化json对象(我在C#中使用json.Net创建的)也保留每个字段的类型信息及其值。
例如,我希望我的json文件采用类似的格式:
{
"fieldString": {
"type": "string",
"value": "my custom string data"
},
"fieldTimeStamp": {
"type": "date",
"value": "2018-12-10T08:25:55.150Z"
},
"fieldNumber": {
"type": "number",
"value": 999999.999
},
"fieldGeopoint": {
"type": "geopoint",
"value": {
"_latitude": 0.0,
"_longitude": 0.0
}
},
}
感谢社区成员提出的问题,这是额外的信息,我希望这将有所帮助。。。
我的实用程序将是数据上传实用程序,它将独立于任何应用程序读取数据。这将从json文件中读取数据,并构造一个正确的对象来调用REST API(任何)。例如,GeoPoint对象,它不是一个基元数据类型,不同的语言可能有不同的名称,与该对象相关的属性。
创建json文件的工具将负责为每个对象提供类型化信息和字段值。我的数据上传实用程序将决定如何解释该GeoPoint以将其传递给其他API,例如,在Azure CosmosDB中,geo-point被称为"point",而在Good world中,它被称为"GeoPoint",其他人可能对相同的基础信息有不同的名称。例如,有些人可能会区分"int"one_answers"float",而另一些人可能不会。
这已经是JSON中内置的功能。网络序列化程序:
如何使用Newtonsoft将对象序列化为具有类型信息的json。Json?
我相信你可以利用这一点:区别实际上是在基元类型和对象类型之间。如果您有一个对象属性,那么它将得到支持,如果它是基元类型(也许不是)。因此,您需要为每个基元类型创建一个单独的类。您可以创建自己的String对象、Date对象、Number对象等等(在C#端)。
此外,您可以直接使用JsonWriter/JsonReader。它们不太难使用,可以让您对协议进行最佳控制。直接代码将使调试变得容易,而且它也会有一个非常好的副作用。(通常,JSON.net使用反射和/或运行时编译的帮助程序类)
尽管我按照@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,
}