【问题标题】:Newtonsoft JSon Deserialize into Primitive typeNewtonsoft JSon 反序列化为原始类型
【发布时间】:2016-02-09 14:58:52
【问题描述】:

在我的 C# 程序中,我正在查询一个 web 服务并以 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.

我真的很迷茫/很好奇如何更新我的代码才能正确解析这两个,我对这个错误消息有点迷茫。任何帮助都将不胜感激!

【问题讨论】:

  • 您的输入不包含双精度,它包含具有valproperty 的对象。为什么您希望能够将其解析为双精度?为什么不尝试与之前相同的方法,例如定义class MyObj{public double val;}
  • @PanagiotisKanavos,我知道这行得通,而且你的回复很有意义,我只是希望有更好的方法/有一种方法可以立即将回复解析为原始类型.
  • 但是你没有有任何双值。如果你这样做了,字符串将采用[123.45,234.56,2343.54] 的形式。你所拥有的实际上是字典
  • 是的,这就是回复的形成方式,我无能为力......这对于复杂的对象非常有用,但是当你只想获得价值时,你会被困住NameValue 对....我现在正在研究一个解决方案,只是希望库中有一些东西/有人写了一些东西来处理这种情况,

标签: c# .net json json.net deserialization


【解决方案1】:

如果您将静态方法更改为返回IEnumerable&lt;T&gt; 而不是采用Action&lt;T&gt;,您将能够以非常简洁自然的方式将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);
        }

【讨论】:

  • 天哪!!! - 我必须检查这段代码,看看它是如何工作的,但这太棒了! - 谢谢你
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多