2017-09-22 22 views
2

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

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转换器,我不知道如果我创造了它正确。我看到了转换器的例子,他们使用existingValue而不是reader.Value。在我的情况下,existingValue总是0.

上述实现是否正确?

+0

'existingValue'是现有的值,因为'Company.Id'永远不会直接分配给属性或从ctor,它将始终为0. – Xiaoy312

+0

我投票结束此问题作为离题,因为它是关于审查工作代码。它属于[CodeReview](https://codereview.stackexchange.com/help/on-topic)。 –

+0

至少在结束我的问题之前,我很清楚从DBC那里得到了很好的见解:)我不知道这是脱离主题。再次感谢DBC的帮助。 – ata6502

回答

0

您的代码基本上是正确。

existingValue是以前存在于父c#模型中的值。通过将它传入转换器,Json.NET允许转换器在populating现有模型或只读集合上工作。举例来说,如果你有一个预分配只读与转换器属性:

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。相反,你应该在invariant format序列如下:

    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. JsonConverter.CanConvert不叫当转换器通过属性应用。但是,如果您将转换器添加到JsonSerializerSettings.Converters,则返回trueCanConvert将是一个问题。相反,我建议要么throwning一个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)); 
    } 
} 

样品fiddle出既严谨和宽容最终转换器的版本。

相关问题