2016-03-08 15 views
5

Il JSON è simile al seguente:Evitare di deserializzazione una stringa di token JSON a una proprietà numerica

{ 
    "x": "50" 
} 

E la classe si presenta così:

public class Test 
{ 
    public float? x { get; set; } 
} 

E quando si utilizza

var test = JsonConvert.DeserializeObject<Test>(json); 

Nessuna eccezione viene lanciata, JSON.NET converte solo il valore stringa "50" in un valore float 50.0.

Questa domanda viene sollevata nel contesto della convalida dell'input. Voglio ottenere un'eccezione, perché la stringa JSON non è conforme al contratto (il campo x dovrebbe essere un vero float).

E non voglio usare annotazioni di proprietà nella classe 'Test'.

Esiste un JsonSerializerSettings che può essere utilizzato per evitare questo?

+0

è possibile contrassegnare il propery con attributo '[JsonIgnore]' –

+6

Cosa vuoi che succeda? – CodeCaster

+0

@ZdeslavVojkovic - Potrei sbagliarmi, ma penso che OP voglia ignorarlo * perché * è tra virgolette. Se è così, OP, questo è sicuramente un disallineamento tra l'output serializzato e le aspettative del consumatore? Non è più una considerazione del design? –

risposta

5

JSON.NET analizza generosamente numeri-in-stringhe ("50") come numeri. Non c'è un modo banale per disattivarlo, per quanto posso trovare.

si potrebbe creare un convertitore personalizzato che non consente questo:

public class NumberConverter : JsonConverter 
{ 
    private readonly Type[] _typesNotToReadAsString = { typeof(float), typeof(float?) }; 

    public override bool CanConvert(Type objectType) 
    { 
     return _typesNotToReadAsString.Any(t => t.IsAssignableFrom(objectType)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JToken token = JToken.Load(reader); 

     if (_typesNotToReadAsString.Contains(objectType) && token.Type == JTokenType.String) 
     { 
      string exceptionString = string.Format("Won't convert string to type {0}", objectType.FullName); 
      throw new JsonSerializationException(exceptionString); 
     } 

     return token.ToObject(objectType); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 

    public override bool CanWrite 
    { 
     get { return false; } 
    } 
} 

Le relazioni convertitore di essere in grado di deserializzare in tipi specificati, in questo caso float e float?, ma configurabile.

In seguito alla deserializzazione, ispeziona il tipo di token. Alcuni tipi di token per proposta ingresso JSON:

  • "50": JTokenType.String
  • 50: JTokenType.Integer
  • 42.1415: JTokenType.Float

questo modo il convertitore può determinare se il token corrente è formattato come desiderato. Quando il tipo di token è una stringa, il convertitore sopra genererà un'eccezione affermando che non converte una stringa nel tipo desiderato.

Se il tipo di token è diverso, il convertitore convertirà il token nel tipo numerico appropriato tramite token.ToObject(objectType). Questo metodo gestirà anche l'input non numerico generando l'eccezione appropriata, ad esempio "Impossibile convertire l'array in singolo"..

Data una classe Foo:

public class Foo 
{ 
    public float Bar { get; set; } 
    public string Baz { get; set; } 
    public float? Qux { get; set; } 
} 

deserializzare una stringa JSON utilizzando sopra convertitore, questo funzionerà:

var jsonString = "{ \"Bar\" : 50, \"Baz\" : \"zaB\", \"Qux\" : 42.1415 }"; 
var foo = JsonConvert.DeserializeObject<Foo>(jsonString, new NumberConverter()); 

Anche se questo sarà buttare:

var jsonString = "{ \"Bar\" : 50, \"Baz\" : \"zaB\", \"Qux\" : \"42.1415\" }"; 
var foo2 = JsonConvert.DeserializeObject<Foo>(jsonString, new NumberConverter()); 
Problemi correlati