2016-02-09 38 views
0

在我的C#程序,我查询一个Web服务,并得到一个答复流回到JSON,看起来是这样的:Newtonsoft JSON反序列化为原始类型

{"val":12345.12},{"val":23456.23},{"val":34567.01},... 

,或者每回答可能超过1值对象:

{"val1":12345.12,"val2":1},{"val1":23456.23,"val2":3},.... 

我有利用Newtonsoft.Json库解析流,并执行每个解析对象的某些动作,一次一个下面的代码:

public void ParseReply<T>(StreamReader sr, Action<T> action) 
{ 
    using (var reader = new JsonTextReader(sr)) 
    { 
     var ser = new JsonSerializer(); 

     while (reader.Read()) 
     { 
      if (reader.TokenType == JsonToken.EndArray) 
       break; 
      action(ser.Deserialize<T>(reader)); 
     } 
    } 
} 

因此,在第二个结果的情况下,我有以下代码:

public class MyObject 
{ 
    public double val1; 
    public double val2; 
} 

然后:

myJson.ParseReply<MyObject>(sr, obj => ...); 

完美。


但是,在第一个回复(每件1倍的值)的情况下,如果我尝试使用我的方法以下列方式:

myJson.ParseReply<double>(sr, dbl => ...); 

我得到一个错误说:

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Double' because the type requires a JSON primitive value (e.g. string, number, boolean, null) to deserialize correctly. 
To fix this error either change the JSON to a JSON primitive value (e.g. string, number, boolean, null) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. 

我真的很失落/好奇我怎么能更新我的代码,以便能够正确解析这两个,我有点在这个错误消息丢失。任何帮助将非常感谢!

+1

您输入不包含双打,它包含的对象以'val'property。你为什么期望能够解析它为双重?为什么不尝试和你一样的事情,比如定义'MyObj {public double val;}'? –

+0

@PanagiotisKanavos,我知道这会起作用,你的回答非常有道理,我只是希望有一个更好的方法来做到这一点/有一种方法可以简单地将答复解析为原始类型。 –

+1

但你*不*有任何双重值。如果你这样做了,字符串的格式应该是'[123.45,234.56,2343.54]'。你有什么实际上是字典 –

回答

1

如果你改变你的静态方法返回一个IEnumerable<T>而不是采取一个Action<T>,您将能够链接在一起在一个非常简洁和自然的方式EnumerableLINQ to JSON方法。因此,如果您有:

public static class JsonExtensions 
{ 
    public static IEnumerable<T> ParseArray<T>(this TextReader textReader) 
    { 
     using (var reader = new JsonTextReader(textReader)) 
     { 
      bool inArray = false; 
      var ser = JsonSerializer.CreateDefault(); 
      while (reader.Read()) 
      { 
       if (reader.TokenType == JsonToken.Comment) 
        continue; 
       if (reader.TokenType == JsonToken.StartArray && !inArray) 
       { 
        inArray = true; 
        continue; 
       } 
       if (reader.TokenType == JsonToken.EndArray) 
        break; 
       yield return ser.Deserialize<T>(reader); 
      } 
     } 
    } 

    public static IEnumerable<JToken> DescendantsAndSelf(this JToken node) 
    { 
     // This method should be present on JToken but is only present on JContainer. 
     if (node == null) 
      return Enumerable.Empty<JToken>(); 
     var container = node as JContainer; 
     if (container != null) 
      return container.DescendantsAndSelf(); 
     else 
      return new[] { node }; 
    } 

    public static bool IsNumeric(this JTokenType type) { return type == JTokenType.Integer || type == JTokenType.Float; } 

    public static bool IsNumeric(this JToken token) { return token == null ? false : token.Type.IsNumeric(); } 
} 

你可以这样做:

 var json = @"[{""val"":12345.12},{""val"":23456.23},{""val"":34567.01}]"; 

     // Select all properties named "val" and transform their values to doubles. 
     foreach (var val in new StringReader(json).ParseArray<JToken>() 
      .Select(t => (double)t.SelectToken("val"))) 
     { 
      Debug.WriteLine(val); 
     } 

     // Select all primitive numeric values 
     foreach (var val in new StringReader(json).ParseArray<JToken>() 
      .SelectMany(t => t.DescendantsAndSelf()) 
      .Where(t => t.IsNumeric()) 
      .Select(t => (double)t)) 
     { 
      Debug.WriteLine(val); 
     } 
+0

圣牛! - 我必须查看这段代码,看看它是如何工作的,但它非常棒! - **谢谢** –

相关问题