好吧,这里的问题似乎是XYZ类 http://revitapisearch.com/html/b9b10e41-46c7-7e9b-bbd9-b6180e328d4d.htm在 Revit 中是不可变的 http://thebuildingcoder.typepad.com/blog/2010/04/xyz-immutable.html, 所以JsonSerializer
无法设置属性。一般情况下处理这个问题的方法是为你的类装饰一个合适的构造函数JsonConstructorAttribute https://stackoverflow.com/questions/9085676/is-there-a-way-to-use-json-net-deserialization-with-immutable-classes- 但你不能那样做,因为XYZ
is a Revit班级,不是你自己的。
解决方案#1
要解决这个问题,您可以子类化XYZ
并用该属性装饰适当的构造函数 - 但是,我不确定 Revit 类是否是密封的,或者如果您实际上将这些子类 XYX 之一传递回 Revit,这是否会产生不可预见的副作用。或者,您可以引入纯粹用于序列化和反序列化的代理类:
public static class XYZProxyExtensions
{
public static XYZProxy ToXYZProxy(this XYZ xyz)
{
return new XYZProxy(xyz.X, xyz.Y, xyz.Z);
}
}
public class XYZProxy
{
public XYZProxy()
{
this.X = this.Y = this.Z = 0;
}
public XYZProxy(double x, double y, double z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public XYZ ToXYZ()
{
return new XYZ(X, Y, Z);
}
public override string ToString()
{
return string.Format("({0},{1},{2})", X, Y, Z);
}
}
完成此操作后,您可以将代理属性添加到自定义类,将它们标记为隐藏在调试器中,并告诉 Json.Net 序列化代理,而不是原始属性:
[JsonObject(MemberSerialization.OptIn)]
public class Points
{
public XYZ bboxmin { get; set; }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[JsonProperty(PropertyName = "bboxmin")]
public XYZProxy bboxminProxy
{
get
{
return bboxmin.ToXYZProxy();
}
set
{
bboxmin = value.ToXYZ();
}
}
}
更多信息请点击这里:http://www.tecsupra.com/serializing-only-some-properties-of-an-object-to-json-using-newtonsoft-json-net/ http://www.tecsupra.com/serializing-only-some-properties-of-an-object-to-json-using-newtonsoft-json-net/和这里:使用 Json.net 序列化时如何更改属性名称? https://stackoverflow.com/questions/8796618/how-can-i-change-property-names-when-serializing-with-json-net
解决方案#2
或者,你可以尝试写你自己的JsonConverter https://stackoverflow.com/questions/20623565/json-net-custom-serialization-deserialization-of-a-third-party-type for XYZ
进而使用 Json.Net 注册它 https://stackoverflow.com/questions/19510532/registering-a-custom-jsonconverter-in-json-net。转换器可能看起来像这样(警告 - 未经测试!)
class XYZConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(XYZ);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var obj = JToken.Load(reader);
if (obj.Type == JTokenType.Array)
{
var arr = (JArray)obj;
if (arr.Count == 3 && arr.All(token => token.Type == JTokenType.Float))
{
return new XYZ(arr[0].Value<double>(), arr[1].Value<double>(), arr[2].Value<double>());
}
}
return null;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var vector = (XYZ)value;
writer.WriteStartArray();
writer.WriteValue(vector.X);
writer.WriteValue(vector.Y);
writer.WriteValue(vector.Z);
writer.WriteEndArray();
}
}
这会产生如下所示的 Json:
"bboxmin": [ -100.0, -100.0, -1000.0 ]
这种格式可能更好也可能更差;您是否正在尝试向某些预先存在的第 3 方库读取和写入文件?]
第二次解决方案更新
您需要创建JsonSerializer
使用适当的设置来调用转换器,只需执行以下操作new JsonSerializer()
不管用。我测试了以下内容,效果很好(这里是我的课程版本Points
只有 4 个字段):
public static class JsonSerializerTest
{
static JsonSerializerTest()
{
// This needs to be done only once, so put it in an appropriate static initializer.
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = new List<JsonConverter> { new XYZConverter() }
};
}
public static void Test()
{
Points points = new Points();
points.bboxmin = new XYZ(-100, -100, -1000);
points.bboxmax = new XYZ( 100, 100, 1000);
points.sboxmin = new XYZ(-10, -10, -100);
points.sboxmax = new XYZ( 10, 10, 100);
try
{
string json;
using (var writer = new StringWriter())
{
JsonSerializer serializer = JsonSerializer.CreateDefault();
serializer.Serialize(writer, points);
json = writer.ToString();
}
Points newPoints = null;
using (var reader = new StringReader(json))
{
JsonSerializer serializer = JsonSerializer.CreateDefault();
newPoints = (Points)serializer.Deserialize(reader, typeof(Points));
}
Debug.Assert(points.bboxmin.IsAlmostEqualTo(newPoints.bboxmin));
Debug.Assert(points.bboxmax.IsAlmostEqualTo(newPoints.bboxmax));
Debug.Assert(points.sboxmin.IsAlmostEqualTo(newPoints.sboxmin));
Debug.Assert(points.sboxmax.IsAlmostEqualTo(newPoints.sboxmax));
}
catch (Exception ex)
{
Debug.Assert(false, ex.ToString());
}
}
}
生成的 Json 输出非常简单且可读:
{"bboxmin":[-100.0,-100.0,-1000.0],"bboxmax":[100.0,100.0,1000.0],"sboxmin":[-10.0,-10.0,-100.0],"sboxmax":[10.0,10.0,100.0]}
这避免了对代理的需求,因此可能是一个更漂亮的解决方案。