2017-09-22 48 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出既嚴謹和寬容最終轉換器的版本。

相關問題