【问题标题】:Problems using JSON.NET with ExpandableObjectConverter使用带有 ExpandableObjectConverter 的 JSON.NET 的问题
【发布时间】:2013-07-07 18:14:01
【问题描述】:

我定义了以下类:

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

【问题讨论】:

标签: c# json vb.net json.net typeconverter


【解决方案1】:

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

【讨论】:

  • 请问您如何“应用上述转换器”?
  • @bboyle1234 在 C# 中,将属性 [TypeConverter(typeof(SerializableExpandableObjectConverter))] 添加到您的类中
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    感谢 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);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-02
      • 1970-01-01
      • 2015-08-29
      相关资源
      最近更新 更多