LINQ to JSON - 来自可能是 JValue 或 JArray 的 JToken 的 NullReferenceException 错误
LINQ to JSON - NullReferenceException error from a JToken that could be either a JValue or JArray
我正在尝试 select 基于数组或值的第一个元素的 roleId 为 4 的所有用户。我怎样才能做到这一点?另外,如何显示 roleId?这是我的 JSON 字符串:
{
"?xml" : {
"@version" : "1.0",
"@encoding" : "UTF-8"
},
"DataFeed" : {
"@FeedName" : "AdminData",
"People" : [{
"id" : "63",
"active": "1",
"firstName" : "Joe",
"lastName" : "Schmoe",
"roleIds" : {
"int" : "4"
}
} , {
"id" : "65",
"active": "1",
"firstName" : "Steve",
"lastName" : "Jobs",
"roleIds" : {
"int" : ["4", "16", "25", "20", "21", "22", "17", "23", "18"]
}
} , {
"id" : "66",
"active": "1",
"firstName" : "Bill",
"lastName" : "Gates",
"roleIds" : {
"int" : ["3", "16", "25", "20"]
}
}
]
}
}
这是我正在使用的查询:
JObject jsonFeed = JObject.Parse(jsonString);
from people in jsonFeed.SelectTokens("DataFeed.People").SelectMany(i => i)
let ids = people["roleIds.int"]
where (int) people["active"] == 1 &&
(ids.Type == JTokenType.Array) ?
((int[]) ids.ToObject(typeof(int[]))).Any(k => k == 4) :
// <-- this looks through all items in the array.
// I just want to compare against the 1st element
(int) ids == 4
select new {
Id = (int) people["id"],
ResAnFName = (string) people["firstName"],
ResAnLName = (string) people["lastName"],
RoleId = ?? // <-- how do I get the roleID displayed
});
我在 ((int[]) ids.ToObject(typeof(int[]))).Any(k => k == 4)
上收到以下错误:
NullReferenceException: Object reference not set to an instance of an
object.
最后,我的结果应该是:Joe Schmoe
& Steve Jobs
,只有。
我做错了什么?
你需要做的
let ids = people.SelectToken("roleIds.int")
而不是
let ids = people["roleIds.int"]
那是因为ids
属性嵌套在roleIds
属性里面,对于嵌套对象的查询,SelectToken()
should be used. JObject.Item(String)
只有returns 具有该确切名称的 属性 -- 可能包括 .
。 IE。您原来的 let
声明适用于以下内容:
{
"roleIds.int": "4"
}
虽然 SelectToken()
必须用于:
{
"roleIds" : {
"int" : "4"
}
}
完整查询:
var query = from people in jsonFeed.SelectTokens("DataFeed.People")
.SelectMany(i => i)
let ids = people.SelectToken("roleIds.int")
where (int)people["active"] == 1 &&
(ids.Type == JTokenType.Array) ?
((int[])ids.ToObject(typeof(int[]))).Any(k => k == 4) :
(int)ids == 4
select new
{
Id = (int)people["id"],
ResAnFName = (string)people["firstName"],
ResAnLName = (string)people["lastName"]
};
工作fiddle。
更新
如果您想将 RoleIds
作为整数数组添加到返回的匿名类型中,您可以这样做:
int desiredRoleId = 4;
var query = from people in jsonFeed.SelectTokens("DataFeed.People")
.SelectMany(i => i)
let ids = people
.SelectToken("roleIds.int")
.SingleOrMultiple()
.Select(t => (int)t)
.ToArray()
where (int?)people["active"] == 1 && ids.Contains(desiredRoleId)
select new
{
Id = (int)people["id"],
RoleIds = ids,
ResAnFName = (string)people["firstName"],
ResAnLName = (string)people["lastName"]
};
使用扩展方法:
public static class JsonExtensions
{
public static IEnumerable<JToken> SingleOrMultiple(this JToken source)
{
if (source == null)
return Enumerable.Empty<JToken>();
IEnumerable<JToken> arr = source as JArray;
return arr ?? new[] { source };
}
}
要获取第一个角色 ID,请将 select
子句更改为:
select new
{
Id = (int)people["id"],
FirstRoleId = ids.FirstOrDefault(),
ResAnFName = (string)people["firstName"],
ResAnLName = (string)people["lastName"]
};
示例 fiddle.
我正在尝试 select 基于数组或值的第一个元素的 roleId 为 4 的所有用户。我怎样才能做到这一点?另外,如何显示 roleId?这是我的 JSON 字符串:
{
"?xml" : {
"@version" : "1.0",
"@encoding" : "UTF-8"
},
"DataFeed" : {
"@FeedName" : "AdminData",
"People" : [{
"id" : "63",
"active": "1",
"firstName" : "Joe",
"lastName" : "Schmoe",
"roleIds" : {
"int" : "4"
}
} , {
"id" : "65",
"active": "1",
"firstName" : "Steve",
"lastName" : "Jobs",
"roleIds" : {
"int" : ["4", "16", "25", "20", "21", "22", "17", "23", "18"]
}
} , {
"id" : "66",
"active": "1",
"firstName" : "Bill",
"lastName" : "Gates",
"roleIds" : {
"int" : ["3", "16", "25", "20"]
}
}
]
}
}
这是我正在使用的查询:
JObject jsonFeed = JObject.Parse(jsonString);
from people in jsonFeed.SelectTokens("DataFeed.People").SelectMany(i => i)
let ids = people["roleIds.int"]
where (int) people["active"] == 1 &&
(ids.Type == JTokenType.Array) ?
((int[]) ids.ToObject(typeof(int[]))).Any(k => k == 4) :
// <-- this looks through all items in the array.
// I just want to compare against the 1st element
(int) ids == 4
select new {
Id = (int) people["id"],
ResAnFName = (string) people["firstName"],
ResAnLName = (string) people["lastName"],
RoleId = ?? // <-- how do I get the roleID displayed
});
我在 ((int[]) ids.ToObject(typeof(int[]))).Any(k => k == 4)
上收到以下错误:
NullReferenceException: Object reference not set to an instance of an object.
最后,我的结果应该是:Joe Schmoe
& Steve Jobs
,只有。
我做错了什么?
你需要做的
let ids = people.SelectToken("roleIds.int")
而不是
let ids = people["roleIds.int"]
那是因为ids
属性嵌套在roleIds
属性里面,对于嵌套对象的查询,SelectToken()
should be used. JObject.Item(String)
只有returns 具有该确切名称的 属性 -- 可能包括 .
。 IE。您原来的 let
声明适用于以下内容:
{
"roleIds.int": "4"
}
虽然 SelectToken()
必须用于:
{
"roleIds" : {
"int" : "4"
}
}
完整查询:
var query = from people in jsonFeed.SelectTokens("DataFeed.People")
.SelectMany(i => i)
let ids = people.SelectToken("roleIds.int")
where (int)people["active"] == 1 &&
(ids.Type == JTokenType.Array) ?
((int[])ids.ToObject(typeof(int[]))).Any(k => k == 4) :
(int)ids == 4
select new
{
Id = (int)people["id"],
ResAnFName = (string)people["firstName"],
ResAnLName = (string)people["lastName"]
};
工作fiddle。
更新
如果您想将 RoleIds
作为整数数组添加到返回的匿名类型中,您可以这样做:
int desiredRoleId = 4;
var query = from people in jsonFeed.SelectTokens("DataFeed.People")
.SelectMany(i => i)
let ids = people
.SelectToken("roleIds.int")
.SingleOrMultiple()
.Select(t => (int)t)
.ToArray()
where (int?)people["active"] == 1 && ids.Contains(desiredRoleId)
select new
{
Id = (int)people["id"],
RoleIds = ids,
ResAnFName = (string)people["firstName"],
ResAnLName = (string)people["lastName"]
};
使用扩展方法:
public static class JsonExtensions
{
public static IEnumerable<JToken> SingleOrMultiple(this JToken source)
{
if (source == null)
return Enumerable.Empty<JToken>();
IEnumerable<JToken> arr = source as JArray;
return arr ?? new[] { source };
}
}
要获取第一个角色 ID,请将 select
子句更改为:
select new
{
Id = (int)people["id"],
FirstRoleId = ids.FirstOrDefault(),
ResAnFName = (string)people["firstName"],
ResAnLName = (string)people["lastName"]
};
示例 fiddle.