做Revit二次开发常会遇到需要使用API所提供的类型来进行操作,坐标为例,常有 XYZ UV 这种类型,而此类数据在序列化为文本后再次读取反序列化时会出现坐标数据无法读取则全部默认置0的情况,为解决此类问题,Newtonsoft.Json需要针对这些第三方提供的类型做自定义的解析设置;
如我们自定义一个类型如下:
public class Demo{
public int id { get; set; }
public string name { get; set; }
public Rect rectangel { get; set; }
}
public class Rect{
public UV center { get; set; }
public List<UV> points { get; set; }
}
这里再Demo中嵌套了一个Rect,其中的类型由UV构成;
此时我们构造实例、输入数据、序列化常规流程走一遍,并保存为文件
public class JsonTest
{
public static string Save()
{
string savePath =@"C:\temp_demo.json";
string demoJson = Init();
File.WriteAllText(savePath, demoJson, Encoding.Unicode);
return savePath;
}
public static string Init()
{
List<Demo> demos = new List<Demo>();
var rectangel0 = new Rect();
rectangel0.center = new UV(1.5, 1.5);
rectangel0.points = new List<UV>(){
new UV(3.0,3.0),
new UV(0.0,3.0),
new UV(0.0,0.0),
new UV(3.0,0.0)
};
var demo0 = new Demo();
demo0.id = 0;
demo0.name = "demo0";
demo0.rectangel = rectangel0;
demos.Add(demo0);
var rectangel1 = new Rect();
rectangel1.center = new UV(2.5, 2.5);
rectangel1.points = new List<UV>(){
new UV(5.0,5.0),
new UV(0.0,5.0),
new UV(0.0,0.0),
new UV(5.0,0.0)
};
var demo1 = new Demo();
demo1.id = 1;
demo1.name = "demo1";
demo1.rectangel = rectangel1;
demos.Add(demo1);
var json = JsonConvert.SerializeObject(demos);
return json;
}
}
然后我们在主程中运行
internal class Program
{
private static void Main(string[] args)
{
string savePath = @"C:\temp_demo.json";
//构造并序列化为字符串
string demoJson = Init();
//写入json文档
File.WriteAllText(savePath, demoJson, Encoding.Unicode);
//读取json文档
string jsonData = File.ReadAllText(savePath);
/*=============================================================*/
//重点:反序列化
// 默认读取API的UV类型会出错 此处提供UV的自定义读取方式
var setting = new JsonSerializerSettings
{
Converters = new List<JsonConverter>
{
new JsonUVConverter(),
//new JsonUVUVConverter(),
}
};
var demos = JsonConvert.DeserializeObject<List<Demo>>(jsonData, setting);
//如果这里仅仅使用默认反序列化,而不加定义 如: JsonConvert.DeserializeObject<List<Demo>>(jsonData)
//则会出现凡是UV参与构件的属性读取后都为0.0值 而我们在init初始化时并非全为0
//故此处使用了JsonSerializerSettings来自定义json读写时针对UV类型的序列化方式 也叫针对属性自定义序列化方式
//这里的 JsonUVConverter类 如下定义
/*=============================================================*/
Console.WriteLine($"correct json:{json}");
Console.ReadKey();
}
}
接下来就是解析的重点 针对类型的自定义json序列化设置,即上述代码的 JsonUVConverter 类 ;
public class JsonUVConverter : JsonConverter
{
//判断是否为需要转换的类型
public override bool CanConvert(Type objectType)
{
return objectType == typeof(UV);
}
//读取时的动作 即 反序列化时操作
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
if (token["U"] != null && token["V"] != null)
{
double u = (double)token["U"];
double v = (double)token["V"];
UV vec = new UV(u, v);
return vec;
}
else
{
return UV.Zero;
}
}
//写入时的动作 即序列化时的操作
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
UV uvValue = (UV)value;
writer.WriteStartObject();
writer.WritePropertyName("u");
writer.WriteValue(uvValue.U);
writer.WritePropertyName("V");
writer.WriteValue(uvValue.V);
writer.WriteEndObject();
}
}
由此 完成带有第三方类型的完整解析 ;