Json字符串反序列化,对象有可能是类,有可能是数组。

卧_槽 2017-01-17 06:06:07
获取第三方API提供的Json数据。

非常蛋疼的是,不知道他们怎么做的反序列化,比如 Results下面如果有多个Result,那么就会是[]包裹的数组,如果只有一个,字符串里面就没有这对中括号。

更蛋疼的是,一个复杂对象下面,有很多这种属性。


Json.net有什么高级特性可以判别这种情况,让反序列化能继续下去么?
...全文
1393 30 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
lower404 2019-07-25
  • 打赏
  • 举报
回复
还有这种 我是不知道这种参数名该怎么封装,都不是合法命名
lower404 2019-07-25
  • 打赏
  • 举报
回复
我在封装极光推送的rest api请求参数时,也遇到了这个问题。 现在就不知道该怎么封装了,头疼。
showjim 2017-01-18
  • 打赏
  • 举报
回复
试试 fastCSharp,这是一个内部 dll,和开源的有些不同,不过是可以反编译的
        public class Rootobject : attribute<Rootobject, Attributes>
        {
            public maybeArray<Match> match;
        }

        public class Attributes
        {
            public DateTime time;
            public string timestamp;
        }

        public class Match : attribute<Match, Attributes1>
        {
            public DateTime time;
            public string group;
            public string hteam;
            public string ateam;
            public Results results;
        }

        public class Attributes1
        {
            public string id;
            public string xsid;
            public string gsmid;
            public DateTime last_updated;
        }

        public class Results
        {
            public string status;
            public Periods periods;
            public Result[] result;
        }

        public class Periods
        {
            public Period[] period;
        }

        public class Period : attribute<Period, Attributes2>
        {
            public Detail detail;
        }

        public class Attributes2
        {
            public string id;
            public string name;
        }

        public class Detail : attribute<Detail, Attributes3>
        {
        }

        public class Attributes3
        {
            public string name;
            public string value;
        }

        public class Result : attribute<Result, Attributes4>
        {
        }

        public class Attributes4
        {
            public string id;
            public string name;
            public string value;
        }
对于 Array 的处理,需要定义自定义解析,比如
        public struct maybeArray<valueType>
        {
            public valueType Value;
            public valueType[] Array;
            public bool IsArray;

            [fastCSharp.emit.jsonParse.custom]
            private unsafe static void parseJson(fastCSharp.emit.jsonParser parser, ref maybeArray<valueType> value)
            {
                if (parser.IsArray())
                {
                    parser.Parse(ref value.Array);
                    value.IsArray = true;
                }
                else parser.Parse(ref value.Value);
            }
        }
对于名称匹配问题也需要自定义解析,比如
        public abstract class attribute<valueType, attributeType>
            where valueType : attribute<valueType, attributeType>
        {
            public attributeType attributes;

            [fastCSharp.emit.jsonParse.unknownName]
            protected unsafe static void jsonParseUnknownName(fastCSharp.emit.jsonParser parser, ref valueType value, ref pointer.size name)
            {
                if (name.Equals("@attributes")) parser.Parse(ref value.attributes);
                else parser.Ignore();
            }
        }
然后就可以正常使用了
            Rootobject value = fastCSharp.emit.jsonParser.Parse<Rootobject>(json);
robake 2017-01-18
  • 打赏
  • 举报
回复
你不会是用了用友的一些api接口吧,他们就这么整的 json数据如果有值的时候是"value",没值的时候就是[],而接口出错的时候json格式变另外的结构了。 所以,我都是先getType(),根据这个去判断是什么类型,再转换。
  • 打赏
  • 举报
回复
Regex.Replace(json1, @"""match"":\{([\s\S]*)\}(?=\})", @"""match"":[{$1}]")
match部分可以这样替换,但你举得例子中,result都是数组,{}直接替换成null,这个就是普通的replace
{"@attributes":{"time":"2017-01-18T01:51:16+00:00","timestamp":"1484704276"},
"match":
{"@attributes":{"id":"3915068","xsid":"0","gsmid":"221925","last_updated":"2017-01-18T01:48:20+00:00"},
"time":"2017-01-18T00:00:00+00:00","group":"BANCAA NCAA Division I > Regular Season-16","hteam":"Fairfield","ateam":"St Peters",
"results":{"status":"Fin",
"result":[
{"@attributes":{"id":"1","name":"CURRENT","value":"55-69"}},
{"@attributes":{"id":"2","name":"FT","value":"55-69"}},
{"@attributes":{"id":"3","name":"HT","value":"27-38"}}],
"periods":{"period":[
{"@attributes":{"id":"1","name":"1Q"},"detail":{"@attributes":{"name":"SCORE","value":"27-38"}}},
{"@attributes":{"id":"2","name":"2Q"},"detail":{"@attributes":{"name":"SCORE","value":"28-31"}}},
{"@attributes":{"id":"3","name":"3Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},
{"@attributes":{"id":"4","name":"4Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},
{"@attributes":{"id":"5","name":"OT"},"detail":{"@attributes":{"name":"SCORE","value":"0-0"}}}]}}}
}



{"@attributes":{"time":"2017-01-18T01:51:16+00:00","timestamp":"1484704276"},
"match":[
{"@attributes":{"id":"3915068","xsid":"0","gsmid":"221925","last_updated":"2017-01-18T01:48:20+00:00"},
"time":"2017-01-18T00:00:00+00:00","group":"BANCAA NCAA Division I > Regular Season-16","hteam":"Fairfield","ateam":"St Peters",
"results":{"status":"Fin",
"result":[
{"@attributes":{"id":"1","name":"CURRENT","value":"55-69"}},
{"@attributes":{"id":"2","name":"FT","value":"55-69"}},
{"@attributes":{"id":"3","name":"HT","value":"27-38"}}],
"periods":{"period":[
{"@attributes":{"id":"1","name":"1Q"},"detail":{"@attributes":{"name":"SCORE","value":"27-38"}}},
{"@attributes":{"id":"2","name":"2Q"},"detail":{"@attributes":{"name":"SCORE","value":"28-31"}}},
{"@attributes":{"id":"3","name":"3Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},
{"@attributes":{"id":"4","name":"4Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},
{"@attributes":{"id":"5","name":"OT"},"detail":{"@attributes":{"name":"SCORE","value":"0-0"}}}]}}},
{"@attributes":{"id":"3915097","xsid":"0","gsmid":"221933","last_updated":"2017-01-18T01:51:12+00:00"},
"time":"2017-01-18T00:00:00+00:00","group":"BANCAA NCAA Division I > Regular Season-16","hteam":"Central Florida","ateam":"South Florida",
"results":{"status":"Fin",
"result":[
{"@attributes":{"id":"1","name":"CURRENT","value":"86-64"}},
{"@attributes":{"id":"2","name":"FT","value":"86-64"}},
{"@attributes":{"id":"3","name":"HT","value":"42-30"}}],
"periods":{"period":[
{"@attributes":{"id":"1","name":"1Q"},"detail":{"@attributes":{"name":"SCORE","value":"42-30"}}},
{"@attributes":{"id":"2","name":"2Q"},"detail":{"@attributes":{"name":"SCORE","value":"44-34"}}},
{"@attributes":{"id":"3","name":"3Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},
{"@attributes":{"id":"4","name":"4Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},
{"@attributes":{"id":"5","name":"OT"},"detail":{"@attributes":{"name":"SCORE","value":"0-0"}}}]}}}]}



{"@attributes":{"time":"2017-01-18T01:51:16+00:00","timestamp":"1484704276"},
"match":[
{"@attributes":{"id":"3915063","xsid":"0","gsmid":"221920","last_updated":"2017-01-18T01:46:34+00:00"},
"time":"2017-01-18T00:00:00+00:00","group":"BANCAA NCAA Division I > Regular Season-16","hteam":"Toledo","ateam":"Bowling Green",
"results":{"status":"2Q","periods":{},"scorers":{}}},
{"@attributes":{"id":"3915068","xsid":"0","gsmid":"221925","last_updated":"2017-01-18T01:48:20+00:00"},
"time":"2017-01-18T00:00:00+00:00","group":"BANCAA NCAA Division I > Regular Season-16","hteam":"Fairfield","ateam":"St Peters",
"results":{"status":"Fin","result":[
{"@attributes":{"id":"1","name":"CURRENT","value":"55-69"}},
{"@attributes":{"id":"2","name":"FT","value":"55-69"}},
{"@attributes":{"id":"3","name":"HT","value":"27-38"}}],
"periods":{"period":[
{"@attributes":{"id":"1","name":"1Q"},"detail":{"@attributes":{"name":"SCORE","value":"27-38"}}},
{"@attributes":{"id":"2","name":"2Q"},"detail":{"@attributes":{"name":"SCORE","value":"28-31"}}},
{"@attributes":{"id":"3","name":"3Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},
{"@attributes":{"id":"4","name":"4Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},
{"@attributes":{"id":"5","name":"OT"},"detail":{"@attributes":{"name":"SCORE","value":"0-0"}}}]
}}}]}
卧_槽 2017-01-18
  • 打赏
  • 举报
回复
引用 14 楼 xuzuning 的回复:
json 可以是别人的,或是用非常规手段获取的。 并不可能对每个 json 都定义一个 实体类。或是说不可能对每个 json 都改一下程序 所以,尽管代码上麻烦一点,自行解析还是值得的
tmd,json还是花钱正规渠道买的。 他们说以前没json,直接xml转的json所以这样。
卧_槽 2017-01-18
  • 打赏
  • 举报
回复
引用 17 楼 starfd 的回复:
给个json实例格式呗 只要json实际value部分不包含{}这两个符号,那就可以用正则替换,{替换成[{,}替换成}],即认为所有的都是数组,当然正则能判断出{}前后是否有[]
最终我把所有对象都定义为object。一次序列化完只有再一个一个判断是否为list或null或单个对象。 办法虽然有点笨拙,好歹是完成了。 结贴。
Forty2 2017-01-18
  • 打赏
  • 举报
回复
你21楼的举例代码表现的是‘可选属性’,比你担心的容易多了。
class Results
{
    public string status;
    public Result[] result;  // 可选
    public Periods periods;  // 可选
    public Scores scorers;   // 可选
}
卧_槽 2017-01-18
  • 打赏
  • 举报
回复
引用 17 楼 starfd 的回复:
给个json实例格式呗 只要json实际value部分不包含{}这两个符号,那就可以用正则替换,{替换成[{,}替换成}],即认为所有的都是数组,当然正则能判断出{}前后是否有[]
同一接口,由于时效性的不同,可能的返回大概有如下三种:
{"@attributes":{"time":"2017-01-18T01:51:16+00:00","timestamp":"1484704276"},"match":{"@attributes":{"id":"3915068","xsid":"0","gsmid":"221925","last_updated":"2017-01-18T01:48:20+00:00"},"time":"2017-01-18T00:00:00+00:00","group":"BANCAA NCAA Division I > Regular Season-16","hteam":"Fairfield","ateam":"St Peters","results":{"status":"Fin","result":[{"@attributes":{"id":"1","name":"CURRENT","value":"55-69"}},{"@attributes":{"id":"2","name":"FT","value":"55-69"}},{"@attributes":{"id":"3","name":"HT","value":"27-38"}}],"periods":{"period":[{"@attributes":{"id":"1","name":"1Q"},"detail":{"@attributes":{"name":"SCORE","value":"27-38"}}},{"@attributes":{"id":"2","name":"2Q"},"detail":{"@attributes":{"name":"SCORE","value":"28-31"}}},{"@attributes":{"id":"3","name":"3Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},{"@attributes":{"id":"4","name":"4Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},{"@attributes":{"id":"5","name":"OT"},"detail":{"@attributes":{"name":"SCORE","value":"0-0"}}}]}}}}
{"@attributes":{"time":"2017-01-18T01:51:16+00:00","timestamp":"1484704276"},"match":[{"@attributes":{"id":"3915068","xsid":"0","gsmid":"221925","last_updated":"2017-01-18T01:48:20+00:00"},"time":"2017-01-18T00:00:00+00:00","group":"BANCAA NCAA Division I > Regular Season-16","hteam":"Fairfield","ateam":"St Peters","results":{"status":"Fin","result":[{"@attributes":{"id":"1","name":"CURRENT","value":"55-69"}},{"@attributes":{"id":"2","name":"FT","value":"55-69"}},{"@attributes":{"id":"3","name":"HT","value":"27-38"}}],"periods":{"period":[{"@attributes":{"id":"1","name":"1Q"},"detail":{"@attributes":{"name":"SCORE","value":"27-38"}}},{"@attributes":{"id":"2","name":"2Q"},"detail":{"@attributes":{"name":"SCORE","value":"28-31"}}},{"@attributes":{"id":"3","name":"3Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},{"@attributes":{"id":"4","name":"4Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},{"@attributes":{"id":"5","name":"OT"},"detail":{"@attributes":{"name":"SCORE","value":"0-0"}}}]}}},{"@attributes":{"id":"3915097","xsid":"0","gsmid":"221933","last_updated":"2017-01-18T01:51:12+00:00"},"time":"2017-01-18T00:00:00+00:00","group":"BANCAA NCAA Division I > Regular Season-16","hteam":"Central Florida","ateam":"South Florida","results":{"status":"Fin","result":[{"@attributes":{"id":"1","name":"CURRENT","value":"86-64"}},{"@attributes":{"id":"2","name":"FT","value":"86-64"}},{"@attributes":{"id":"3","name":"HT","value":"42-30"}}],"periods":{"period":[{"@attributes":{"id":"1","name":"1Q"},"detail":{"@attributes":{"name":"SCORE","value":"42-30"}}},{"@attributes":{"id":"2","name":"2Q"},"detail":{"@attributes":{"name":"SCORE","value":"44-34"}}},{"@attributes":{"id":"3","name":"3Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},{"@attributes":{"id":"4","name":"4Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},{"@attributes":{"id":"5","name":"OT"},"detail":{"@attributes":{"name":"SCORE","value":"0-0"}}}]}}}]}
{"@attributes":{"time":"2017-01-18T01:51:16+00:00","timestamp":"1484704276"},"match":[{"@attributes":{"id":"3915063","xsid":"0","gsmid":"221920","last_updated":"2017-01-18T01:46:34+00:00"},"time":"2017-01-18T00:00:00+00:00","group":"BANCAA NCAA Division I > Regular Season-16","hteam":"Toledo","ateam":"Bowling Green","results":{"status":"2Q","periods":{},"scorers":{}}},{"@attributes":{"id":"3915068","xsid":"0","gsmid":"221925","last_updated":"2017-01-18T01:48:20+00:00"},"time":"2017-01-18T00:00:00+00:00","group":"BANCAA NCAA Division I > Regular Season-16","hteam":"Fairfield","ateam":"St Peters","results":{"status":"Fin","result":[{"@attributes":{"id":"1","name":"CURRENT","value":"55-69"}},{"@attributes":{"id":"2","name":"FT","value":"55-69"}},{"@attributes":{"id":"3","name":"HT","value":"27-38"}}],"periods":{"period":[{"@attributes":{"id":"1","name":"1Q"},"detail":{"@attributes":{"name":"SCORE","value":"27-38"}}},{"@attributes":{"id":"2","name":"2Q"},"detail":{"@attributes":{"name":"SCORE","value":"28-31"}}},{"@attributes":{"id":"3","name":"3Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},{"@attributes":{"id":"4","name":"4Q"},"detail":{"@attributes":{"name":"SCORE","value":"-"}}},{"@attributes":{"id":"5","name":"OT"},"detail":{"@attributes":{"name":"SCORE","value":"0-0"}}}]}}}]}
注意对象 Match Result, 可能是对象,可能是数组。而且不排除其他属性,如SCORE,detail等,也可能是数组
Forty2 2017-01-18
  • 打赏
  • 举报
回复
引用 19 楼 Forty2 的回复:
...根据JSON规则,空白字符外,第一个字符只能是数组的[,对象的{,字符串的引号",null的n,和数字0~9。
还有true和false。
Forty2 2017-01-18
  • 打赏
  • 举报
回复
引用 15 楼 Forty2 的回复:
我认为这是"第三方API"的设计错误。...
另外一种补救是先判断第一个有效字符。 根据JSON规则,空白字符外,第一个字符只能是数组的[,对象的{,字符串的引号",null的n,和数字0~9。 可以就此来判断json是否是数组。

// 方法三:
static Result[] Deserialize(string json)
{
    var firstChar = json.FirstOrDefault(x => !char.IsWhiteSpace(x));
    if (firstChar == '[') return JsonConvert.DeserializeObject<Result[]>(json);

    var r = JsonConvert.DeserializeObject<Result>(json);
    return r == null ? null : new Result[] { r };
}
卧_槽 2017-01-18
  • 打赏
  • 举报
回复
引用 12 楼 sp1234 的回复:
[quote=引用 6 楼 yuwenge 的回复:] [quote=引用 3 楼 stherix 的回复:] 任何json反序列化工具都能自动识别这种情况吧 比如newstonsoft.json var Object =JavaScriptConvert.DeserializeObject(str); 然后判断Object is JObject//JArray/JValue之类的
如果只有一层有这个情况,您说的就可以解决了。问题是每一层都可能有这种情况。[/quote] 那是因为你不懂反序列化之前先要定义实体类型。如果你定义实体类型,一个类型 A 的属性中用到了 A,而内部的 A 类型的属性引用的对象自然也还是可能有自己的 A 类型的属性,这有什么可大惊小怪的? 建议学好 .net 基本类型编程,再学“反序列化”。[/quote] 就是没法定义实体类啊。 类型A中有属性B 但是Json字符串中的属性B是不确定的,可能会是 B[ ]也可能是B 而B类型的属性中也可能出现这种情况。 你的理解能力有待提高啊。
  • 打赏
  • 举报
回复
给个json实例格式呗 只要json实际value部分不包含{}这两个符号,那就可以用正则替换,{替换成[{,}替换成}],即认为所有的都是数组,当然正则能判断出{}前后是否有[]
by_封爱 版主 2017-01-18
  • 打赏
  • 举报
回复
这个比较尴尬了. 只能判断 或者转换异常 在换个方式转化
Forty2 2017-01-18
  • 打赏
  • 举报
回复
引用 楼主 yuwenge 的回复:
Json.net有什么高级特性可以判别这种情况,让反序列化能继续下去么?
我认为这是"第三方API"的设计错误。 反系列化的时候可以这样补救: 方法一、先尝试数组,如果抛出异常,再尝试反系列化单个Result 方法二、如果你不喜欢异常,可以先系列化成JToken,判断后在把JToken转成目标。

class Result
{
    public int Id { get; set; }
}
static void Main(string[] args)
{
    var json = "[{'Id':1},{'Id':2}]";
    var tk= JToken.Parse(json);
    if (tk is JArray)
    {
        Result[] rs = tk.ToObject<Result[]>();
    }
    else
    {
        Result r = tk.ToObject<Result>();
    }
}
xuzuning 2017-01-17
  • 打赏
  • 举报
回复
json 可以是别人的,或是用非常规手段获取的。 并不可能对每个 json 都定义一个 实体类。或是说不可能对每个 json 都改一下程序 所以,尽管代码上麻烦一点,自行解析还是值得的
Poopaye 2017-01-17
  • 打赏
  • 举报
回复
总有些已知的规则存在吧 或者创建个类包装一下总行了吧
class ArrayWrapper<T>
{
	T _a;
	T[] _b;

	public ArrayWrapper(object o)
	{
		if (o is T)
			_a = (T)o;
		else if (o is T[])
			_b = (T[])o;
	}

	public int Count
	{
		get { return _a == null ? (_b == null ? 0 : _b.Length) : 1; }
	}

	public T this[int index]
	{
		get { return _a == null ? (_b == null ? default(T) : _b[index]) : (index == 0 ? _a : default(T)); }
	}
}
  • 打赏
  • 举报
回复
引用 6 楼 yuwenge 的回复:
[quote=引用 3 楼 stherix 的回复:] 任何json反序列化工具都能自动识别这种情况吧 比如newstonsoft.json var Object =JavaScriptConvert.DeserializeObject(str); 然后判断Object is JObject//JArray/JValue之类的
如果只有一层有这个情况,您说的就可以解决了。问题是每一层都可能有这种情况。[/quote] 那是因为你不懂反序列化之前先要定义实体类型。如果你定义实体类型,一个类型 A 的属性中用到了 A,而内部的 A 类型的属性引用的对象自然也还是可能有自己的 A 类型的属性,这有什么可大惊小怪的? 建议学好 .net 基本类型编程,再学“反序列化”。
  • 打赏
  • 举报
回复
引用 楼主 yuwenge 的回复:
获取第三方API提供的Json数据。 非常蛋疼的是,不知道他们怎么做的反序列化,比如 Results下面如果有多个Result,那么就会是[]包裹的数组,如果只有一个,字符串里面就没有这对中括号。 更蛋疼的是,一个复杂对象下面,有很多这种属性。 Json.net有什么高级特性可以判别这种情况,让反序列化能继续下去么?
那你说了半天,你要反序列化为什么类型的对象?你所谓的“反序列化”是真正基于确定的实体类吗?
wanghui0380 2017-01-17
  • 打赏
  • 举报
回复
这个不是很好办,使用上可以用dynamic接收 但是dynamic没有提示,所以得根据调用上下文确定,使用上比较别扭
加载更多回复(9)

111,097

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧