首页 文章

(De-)序列化类似于Microsoft的已知类型

提问于
浏览
4

到目前为止,我将业务对象序列化和反序列化为格式为JSON的数据传输对象(DTO) . DTO标有DataContract属性 . 一个小例子:

[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}

是否有可能使用“__type”和 Contract 命名空间而不是“$ type”和类组装组合将Json.NET序列化为符合Microsoft的JSON字符串?我正在使用.NET 3.5 .

提前致谢!

1 回答

  • 0

    不幸的是,似乎无法调整属性名称,因为它在内部JsonTypeReflector.cs class中声明为:

    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 属性的呈现 .

    Example

    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);
    

    Result

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

    P.S.

    您也可以使用DataMember.Order指定订单,如下所示:

    [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; }
    }
    

相关问题