将JSON.NET与ExpandableObjectConverter一起使用时出现问题

本文关键字:问题 一起 JSON NET ExpandableObjectConverter | 更新日期: 2023-09-27 18:21:40

我定义了以下类:

<TypeConverter(GetType(ExpandableObjectConverter))>
<DataContract()>
Public Class Vector3
   <DataMember()> Public Property X As Double
   <DataMember()> Public Property Y As Double
   <DataMember()> Public Property Z As Double
   Public Overrides Function ToString() As String
      Return String.Format("({0}, {1}, {2})",
                           Format(X, "0.00"),
                           Format(Y, "0.00"),
                           Format(Z, "0.00"))
   End Function
End Class

使用DataContractJsonSerializer,我收到了预期的以下JSON:

{
  "Vector": {
    "X": 1.23,
    "Y": 4.56,
    "Z": 7.89
  }
}

但是,JSON.NET生成:

{
  "Vector": "(1.23, 4.56, 7.89)"
}

如果我从类中删除ExpandableObjectConverter属性,JSON.NET将按预期生成结果(与DataContractJsonSerializer相同)。

不幸的是,我需要ExpandableObjectConverter,这样类才能使用属性网格。

有什么方法可以告诉JSON.NET忽略ExpandableObjectConverters吗?

我更喜欢使用JSON.NET而不是DataContractJsonSerializer,因为将枚举序列化为其字符串表示要容易得多。

将JSON.NET与ExpandableObjectConverter一起使用时出现问题

虽然我很欣赏Rivers的回答,但我确实在寻找一种自动忽略所有可扩展对象转换器的解决方案(就像DataContractJsonSerializer所做的那样),而不是为每个有问题的类构建一个自定义JsonConverter。

我发现了以下两种解决方案:

  1. 请改用内置的DataContractJsonSerializer(以牺牲JSON.NET的一些其他便利性为代价)
  2. 使用自定义的ExpandableObjectConverter(请参见下文)

由于默认的ExpandableObjectConverter支持转换为字符串/从字符串转换,因此JSON.NET正在使用字符串序列化类。为了抵消这一点,我创建了自己的可扩展对象转换器,它不允许转换到字符串或从字符串转换。

Imports System.ComponentModel
Public Class SerializableExpandableObjectConverter
   Inherits ExpandableObjectConverter
   Public Overrides Function CanConvertTo(context As System.ComponentModel.ITypeDescriptorContext, destinationType As System.Type) As Boolean
      If destinationType Is GetType(String) Then
         Return False
      Else
         Return MyBase.CanConvertTo(context, destinationType)
      End If
   End Function
   Public Overrides Function CanConvertFrom(context As System.ComponentModel.ITypeDescriptorContext, sourceType As System.Type) As Boolean
      If sourceType Is GetType(String) Then
         Return False
      Else
         Return MyBase.CanConvertFrom(context, sourceType)
      End If
   End Function
End Class

应用上面的转换器可以完美地与JSON.NET和属性网格控件配合使用!

感谢JRS发布此消息。C#的用户可以使用VB:的翻译

public class SerializableExpandableObjectConverter : ExpandableObjectConverter
{
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        if(destinationType == typeof(string))
        {
            return false;
        }
        else
        {
            return base.CanConvertTo(context, destinationType);
        }
    }
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        if(sourceType == typeof(string))
        {
            return false;
        }
        else
        {
            return base.CanConvertFrom(context, sourceType);
        }
    }
}

由于您正在指定一个TypeConverter,Json.net会使用它。为了解决这个问题,请使用LINQ to Json创建一个JsonConverter,以使用您需要的格式:

Public Class Vector3Converter
    Inherits JsonConverter
Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
    Dim vector = DirectCast(value, Vector3)
    serializer.Serialize(writer, New JObject() From { _
        {"X", vector.X}, _
        {"Y", vector.Y}, _
        {"Z", vector.Z} _
    })
End Sub
Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
    Dim jObject = serializer.Deserialize(Of JObject)(reader)
    Return New Vector3() With { _
        Key .X = CDbl(jObject("X")), _
        Key .Y = CDbl(jObject("Y")), _
        Key .Z = CDbl(jObject("Z")) _
    }
End Function
Public Overrides Function CanConvert(objectType As Type) As Boolean
    Return objectType = GetType(Vector3)
End Function
End Class

然后,将其分配给您的类型:

<TypeConverter(GetType(System.ComponentModel.ExpandableObjectConverter))> _
<DataContract> _
<JsonConverter(GetType(Vector3Converter))> _
Public Class Vector3
End Class

我最初使用C#来实现这一点,并使用VB的在线转换器,所以它可能有点偏离。