C#动态对象,根据字符串路径修改属性
C# dynamic object, modify properties based on string paths
用例在概念上非常简单。我收到一个 json 负载,它在根级别上有两个属性:
instructions
base
说明是我应该应用到基础 json 对象上的一组说明。
例如-根据以下有效载荷,
- 我应该遍历到基础 属性 的
defaultWidgets
内的小部件。
- 然后将其完全替换为
patchedValue
. 的值
输入负载:
{
"instructions": [
{
"patchedPath": "defaultWidget.widgets",
"patchedValue": false,
}
],
"base": {
"defaultWidget": {
"hash": "ktocle2l0u527",
"layout": "6|6",
"managerId": "defaultWidget",
"widgets": [
{
"managerId": "defaultWidget",
"widgetId": "invCreateWid7",
"type": "standard",
"manifestPath": "nexxe.standard-section@0.0.0-next.11",
"defaultInputManifestPath": "nexxe.input@0.0.1-alpha.49",
"title": "scannedInvoice",
"children": [
{
"name": "tom"
}
],
"hash": "ktocle2lrgps9",
"directives": ""
}
]
}
}
}
结果应该是:
{
"base": {
"defaultWidget": {
"hash": "ktocle2l0u527",
"layout": "6|6",
"managerId": "defaultWidget",
"widgets": false
}
}
}
代码:
var stringPayload = "{ \"instructions\": [ { \"patchedPath\": \"defaultWidget.widgets\", \"patchedValue\": false, } ], \"base\": { \"defaultWidget\": { \"hash\": \"ktocle2l0u527\", \"layout\": \"6|6\", \"managerId\": \"defaultWidget\", \"widgets\": [ { \"managerId\": \"defaultWidget\", \"widgetId\": \"invCreateWid7\", \"type\": \"standard\", \"manifestPath\": \"nexxe.standard-section@0.0.0-next.11\", \"defaultInputManifestPath\": \"nexxe.input@0.0.1-alpha.49\", \"title\": \"scannedInvoice\", \"children\": [ { \"name\": \"tom\" } ], \"hash\": \"ktocle2lrgps9\", \"directives\": \"\" } ] } }}";
var parsedPayload = JsonConvert.DeserializeObject(stringPayload);
var baseJ = parsedPayload.GetType().GetProperty("instructions").GetValue(parsedPayload, null);
string jsonString = JsonConvert.SerializeObject(parsedPayload);
我卡在最开始的步骤上了,我得到:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
System.Type.GetProperty(...) returned null.
QuickWatch 是这么说的:
在这种情况下,DeserializeObject
返回的是 JObject
,因此您可以首先转换为它:
var parsedPayload = (JObject) JsonConvert.DeserializeObject(stringPayload);
然后抓指令和目标改变:
var instructions = (JArray) parsedPayload["instructions"]; // cast to JArray
var result = parsedPayload["base"];
然后我们可以查看说明并应用它们:
foreach (var instruction in instructions) {
// grab target path and value
var targetPath = (string) ((JValue)instruction["patchedPath"]).Value;
var targetValue = (JValue)instruction["patchedValue"];
// temp variable to traverse the path
var target = result;
foreach (var part in targetPath.Split('.')) {
target = target[part];
}
// replace the value
target.Replace(targetValue);
}
现在结果包含应用指令后的基础内容。
使用 Json.NET 你可以这样做:
var json = File.ReadAllText("sample.json");
var semiParsedJson = JObject.Parse(json);
var instructions = (JArray)semiParsedJson["instructions"];
var @base = semiParsedJson["base"];
foreach (var instruction in instructions)
{
var path = (string)instruction["patchedPath"];
var newValue = (string)instruction["patchedValue"];
var toBeReplaced = @base.SelectToken(path);
toBeReplaced.Replace(newValue);
}
JObject.Parse
解析 json 字符串
- 使用索引运算符
[]
我们检索两个顶级节点。 - 其中之一是一个数组(这就是为什么有一个明确的 JArray
转换)
- 另一个是
JToken
- 我们遍历数组并检索
path
和 newvalue
- 我们使用
SelectToken
获取所需的节点,然后通过 Replace
方法应用替换。
请记住,此解决方案并非万无一失。您可能需要将索引器运算符更改为 TryGetValue
,以便能够在对 JToken
.
执行任何操作之前检查是否存在
您还需要检查 patchedPath
是否有效。
用例在概念上非常简单。我收到一个 json 负载,它在根级别上有两个属性:
instructions
base
说明是我应该应用到基础 json 对象上的一组说明。
例如-根据以下有效载荷,
- 我应该遍历到基础 属性 的
defaultWidgets
内的小部件。 - 然后将其完全替换为
patchedValue
. 的值
输入负载:
{
"instructions": [
{
"patchedPath": "defaultWidget.widgets",
"patchedValue": false,
}
],
"base": {
"defaultWidget": {
"hash": "ktocle2l0u527",
"layout": "6|6",
"managerId": "defaultWidget",
"widgets": [
{
"managerId": "defaultWidget",
"widgetId": "invCreateWid7",
"type": "standard",
"manifestPath": "nexxe.standard-section@0.0.0-next.11",
"defaultInputManifestPath": "nexxe.input@0.0.1-alpha.49",
"title": "scannedInvoice",
"children": [
{
"name": "tom"
}
],
"hash": "ktocle2lrgps9",
"directives": ""
}
]
}
}
}
结果应该是:
{
"base": {
"defaultWidget": {
"hash": "ktocle2l0u527",
"layout": "6|6",
"managerId": "defaultWidget",
"widgets": false
}
}
}
代码:
var stringPayload = "{ \"instructions\": [ { \"patchedPath\": \"defaultWidget.widgets\", \"patchedValue\": false, } ], \"base\": { \"defaultWidget\": { \"hash\": \"ktocle2l0u527\", \"layout\": \"6|6\", \"managerId\": \"defaultWidget\", \"widgets\": [ { \"managerId\": \"defaultWidget\", \"widgetId\": \"invCreateWid7\", \"type\": \"standard\", \"manifestPath\": \"nexxe.standard-section@0.0.0-next.11\", \"defaultInputManifestPath\": \"nexxe.input@0.0.1-alpha.49\", \"title\": \"scannedInvoice\", \"children\": [ { \"name\": \"tom\" } ], \"hash\": \"ktocle2lrgps9\", \"directives\": \"\" } ] } }}";
var parsedPayload = JsonConvert.DeserializeObject(stringPayload);
var baseJ = parsedPayload.GetType().GetProperty("instructions").GetValue(parsedPayload, null);
string jsonString = JsonConvert.SerializeObject(parsedPayload);
我卡在最开始的步骤上了,我得到:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
System.Type.GetProperty(...) returned null.
QuickWatch 是这么说的:
在这种情况下,DeserializeObject
返回的是 JObject
,因此您可以首先转换为它:
var parsedPayload = (JObject) JsonConvert.DeserializeObject(stringPayload);
然后抓指令和目标改变:
var instructions = (JArray) parsedPayload["instructions"]; // cast to JArray
var result = parsedPayload["base"];
然后我们可以查看说明并应用它们:
foreach (var instruction in instructions) {
// grab target path and value
var targetPath = (string) ((JValue)instruction["patchedPath"]).Value;
var targetValue = (JValue)instruction["patchedValue"];
// temp variable to traverse the path
var target = result;
foreach (var part in targetPath.Split('.')) {
target = target[part];
}
// replace the value
target.Replace(targetValue);
}
现在结果包含应用指令后的基础内容。
使用 Json.NET 你可以这样做:
var json = File.ReadAllText("sample.json");
var semiParsedJson = JObject.Parse(json);
var instructions = (JArray)semiParsedJson["instructions"];
var @base = semiParsedJson["base"];
foreach (var instruction in instructions)
{
var path = (string)instruction["patchedPath"];
var newValue = (string)instruction["patchedValue"];
var toBeReplaced = @base.SelectToken(path);
toBeReplaced.Replace(newValue);
}
JObject.Parse
解析 json 字符串- 使用索引运算符
[]
我们检索两个顶级节点。 - 其中之一是一个数组(这就是为什么有一个明确的JArray
转换) - 另一个是
JToken
- 我们遍历数组并检索
path
和newvalue
- 我们使用
SelectToken
获取所需的节点,然后通过Replace
方法应用替换。
请记住,此解决方案并非万无一失。您可能需要将索引器运算符更改为 TryGetValue
,以便能够在对 JToken
.
您还需要检查 patchedPath
是否有效。