JsonConverter and EntityData



我正在使用Azure使用数据库优先的EF方法。Azure Web服务中我的一个实体之一定义如下:

public class Company : EntityData
{
    public string CompanyName { get; set; }
}

它从EntityData继承ID属性。ID属性是类型字符串。

在客户端,我有以下实体:

class Company
{
    [JsonConverter(typeof(IntConverter))]
    public int Id { get; set; }
    public string CompanyName { get; set; }
}

如上所述,我需要将ID从字符串转换为int。

我已经创建了以下JSON转换器:

class IntConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }
    public override object ReadJson(JsonReader reader, Type objectType, 
        object existingValue, JsonSerializer serializer)
    {
        if (reader.Value == null)
            return 0;
        int num;
        if (Int32.TryParse(reader.Value.ToString(), out num))
            return num;
        else
            return 0;
    }
    public override void WriteJson(JsonWriter writer, object value, 
        JsonSerializer serializer)
    {
        serializer.Serialize(writer, value.ToString());
    }
}

它工作正常,但是由于这是我的第一个JSON转换器,因此我不确定是否正确创建了它。我看到了转换器的示例,他们使用了现有价值,而不是读取器。就我而言,现有值始终为0。

上述实施是否正确?

您的代码基本上是正确的。

existingValue是先前存在于父c#模型中的值。通过将其传递到转换器中,JSON.NET允许转换器在填充现有模型或仅读取集合时工作。例如,如果您具有带有转换器的预先读取的属性:

public class RootObject
{
    readonly ObservableCollection<SomeClass> _collection = new ObservableCollection<SomeClass>();
    [JsonConverter(typeof(ObservableCollectionConverter<SomeClass>>)]
    public ObservableCollection<SomeClass> { get { return _collection; } }
}

然后,ObservableCollectionConverter<SomeClass>ReadJson()方法将通过预先分配的_collection值并能够将项目添加到它。

话虽如此,有一些改进要做:

  1. WriteJson()中,您致电value.ToString()ToString()有可能返回具有文化特定的字符串,例如可能会插入NumberGroupSeparator的小数点。相反,您应该以不变格式序列化如下:

    public override void WriteJson(JsonWriter writer, object value,
        JsonSerializer serializer)
    {
        // Int32 implements the IConvertible interface which has a ToString() overload
        // that takes an IFormatProvider specification.  Pass the invariant format to guarantee
        // identical serialization in all cultures.
        var convertible = (IConvertible)value;
        serializer.Serialize(writer, convertible.ToString(NumberFormatInfo.InvariantInfo));
    }
    
  2. ReadJson()中需要进行类似的修复:

        int num;
        if (Int32.TryParse(reader.Value.ToString(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num))
            return num;
        else
            return 0;
    
  3. 您的ReadJson()与意外数据没有弹性。例如,如果传递的JSON实际上具有数组或对象值(例如{"unexpectedProperty": "unexpectedValue"}),则JsonReader将无法正确地提出到输入末尾。您应该检查reader.TokenType并适当处理不良数据,例如:

    public override object ReadJson(JsonReader reader, Type objectType,
        object existingValue, JsonSerializer serializer)
    {
        switch (reader.TokenType)
        {
            case JsonToken.Null:
                return null;
            case JsonToken.Integer:
                // Input was already an integer.  Return it
                return (int)JToken.Load(reader);
            case JsonToken.String:
                {
                    int num;
                    if (Int32.TryParse(reader.Value.ToString(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num))
                        return num;
                    else
                        return 0;
                }
            default:
                throw new JsonSerializationException(string.Format("Unexpected token {0} at path {1}", reader.TokenType, reader.Path));
        }
    

    或,如果您不愿意消耗并丢弃意外数据而不抛出异常(我不建议这样做),则可以使用JsonReader.Skip()

            default:
                Debug.WriteLine(string.Format("Unexpected token {0} at path {1}", reader.TokenType, reader.Path));
                reader.Skip();
                return 0;
    
  4. 当通过属性应用转换器时,
  5. JsonConverter.CanConvert未调用。但是,如果将转换器添加到JsonSerializerSettings.Converters中,那么从CanConvert返回true将是一个问题。相反,我建议抛出NotImplementedException或正确实现该方法:

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(int) || objectType == typeof(int?);
    }
    

因此,您的最终转换器可能看起来像:

class IntConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(int) || objectType == typeof(int?);
    }
    public override object ReadJson(JsonReader reader, Type objectType,
        object existingValue, JsonSerializer serializer)
    {
        switch (reader.TokenType)
        {
            case JsonToken.Null:
                return null;
            case JsonToken.Integer:
                // Input was already an integer.  Return it
                return (int)JToken.Load(reader);
            case JsonToken.String:
                {
                    int num;
                    if (Int32.TryParse(reader.Value.ToString(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num))
                        return num;
                    else
                        return 0;
                }
            default:
                throw new JsonSerializationException(string.Format("Unexpected token {0} at path {1}", reader.TokenType, reader.Path));
        }
    }
    public override void WriteJson(JsonWriter writer, object value,
        JsonSerializer serializer)
    {
        // Int32 implements the IConvertible interface which has a ToString() overload
        // that takes an IFormatProvider specification.  Pass the invariant format to guarantee
        // identical serialization in all cultures.
        var convertible = (IConvertible)value;
        serializer.Serialize(writer, convertible.ToString(NumberFormatInfo.InvariantInfo));
    }
}

样品小提琴显示了最终转换器的严格和耐受版本。

相关内容

  • 没有找到相关文章

最新更新