(反)序列化已知类型类似于微软



到目前为止,我已经使用Microsoft的DataContractJsonSerializer将业务对象序列化和反序列化为格式化为JSON的数据传输对象(DTO)。dto用datcontract属性进行标记。一个小例子:

[DataContract(Name = "Geometry", Namespace = "myContract.com/dto")]
[KnownType(typeof(Point))]
[KnownType(typeof(Line))]
public class Geometry
{
}
[DataContract(Name = "Point", Namespace = "myContract.com/dto")]
public class Point : Geometry
{
    [DataMember(Name = "x")]
    public double X { get; set; }
    [DataMember(Name = "y")]
    public double Y { get; set; }
}
[DataContract(Name = "Line", Namespace = "myContract.com/dto")]
public class Line: Geometry
{
    [DataMember(Name = "start")]
    public Point Start { get; set; }
    [DataMember(Name = "end")]
    public Point End { get; set; }
}

被序列化为:

"geometry":{"__type":"Point:myContract.com/dto","x":23133.75569999963,"y":21582.385849999264}

由于性能问题,我切换到Newtonsoft Json.NET。当使用它时,JSON字符串看起来像这样:

"geometry":{"$type":"A.B.C.Point, A.B.C","x":23133.75569999963,"y":21582.385849999264}

是否有可能用Json序列化对象。. NET变成微软符合JSON字符串使用"__type"和合同命名空间,而不是"$type"和类汇编组合?我使用的是。net 3.5。

提前感谢!

不幸的是,似乎不可能调整属性名,因为它在内部 JsonTypeReflector.cs类中声明为:

public const string TypePropertyName = "$type";

注意:另一方面,类型的属性值可以自定义,SerializationBinder类就是用于这个目的的示例演示如何指定自定义类型属性值。


我将提出以下解决方案,允许编写自定义类型属性。首先,我们需要引入具有type属性的基实体类(或修改Geometry类),如下所示
[DataContract(Name = "Entity", Namespace = "myContract.com/dto")]
public abstract class Entity
{
    [DataMember(Name = "__type", Order = 0)]
    public string EntityTypeName
    {
        get
        {
            var typeName = GetType().Name;
            if (Attribute.IsDefined(GetType(), typeof(DataContractAttribute)))
            {
                var attribute = GetType().GetCustomAttributes(typeof(DataContractAttribute), true).FirstOrDefault() as DataContractAttribute;
                if (attribute != null) typeName = typeName + ":" + attribute.Namespace;
            }
            return typeName;
        }
    }
}

修改Geometry类:

[DataContract(Name = "Geometry", Namespace = "myContract.com/dto")]
[KnownType(typeof(Point))]
[KnownType(typeof(Line))]
public class Geometry : Entity
{
}

最后一步,将JsonSerializerSettings.TypeNameHandling设置为TypeNameHandling.None,以便反序列化器跳过$type属性的呈现。

  var point = new Point { X = 23133.75569999963, Y = 21582.385849999264 };
  var jsonPoint = JsonConvert.SerializeObject(point, new JsonSerializerSettings
  {
       TypeNameHandling = TypeNameHandling.None,   //do not write type property(!)
  });
  Console.WriteLine(jsonPoint);
结果

{"__type":"Point:myContract.com/dto","x":23133.75569999963,"y":21582.385849999264}

注:

您也可以使用DataMember指定顺序。如下图所示:

[DataContract(Name = "Point", Namespace = "myContract.com/dto")]
public class Point : Geometry
{
    [DataMember(Name = "x",Order = 1)]
    public double X { get; set; }
    [DataMember(Name = "y", Order = 2)]
    public double Y { get; set; }
}
[DataContract(Name = "Line", Namespace = "myContract.com/dto")]
public class Line : Geometry
{
    [DataMember(Name = "start", Order = 1)]
    public Point Start { get; set; }
    [DataMember(Name = "end", Order = 2)]
    public Point End { get; set; }
}

最新更新