9

我定义了以下类:

<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因为将枚举序列化为其字符串表示形式要容易得多。

4

3 回答 3

13

尽管我很欣赏 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 和属性网格控件完美结合!

于 2013-07-15T21:06:12.217 回答
1

由于您指定了 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,所以它可能有点偏离。

于 2013-07-11T04:54:24.123 回答
1

感谢 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);
        }
    }
}
于 2021-08-08T20:07:48.640 回答