将对象从 JSON 数组转换为 C# 中的自定义类 [英] Casting objects from JSON array to custom classes in C#
问题描述
我正在使用 Visual Studio 自动生成的 REST Web 应用程序项目结构来创建使用 JSON 输入的 RESTful API.
在不涉及太多细节的情况下,我尝试定义这样的 JSON 结构:
示例 1:
操作":{类型":存在",参数":[{"ColumnName": "SomeColumnA",行":2}]}
示例 2:
操作":{"类型": "添加",参数":[{"类型": "添加",参数":[{"columnName": "SomeColumnB",行":12},{"columnName": "SomeColumnC",行":18}]},20]}
operation
表示任意数量的基本数据库操作之一以及这些操作的参数.在我的第一个示例中,操作是 EXIST
,它应该检查数据库单元格以查看值是否存在.此操作的 args
只是一个包含要检查的单元格的列和行信息的对象(我称之为 Value
).在我的第二个示例中,函数是 ADD
,它应该将两个值相加并返回总和.这里,参数是一个常数 20 和一个嵌套的 ADD
函数,它本身需要两个 Values
.因此,一般来说,args
数组可以采用原始值、另一个嵌套的 operation
或代表要从中读取实际值的单元格的一对值.这里的最终目标是创建一个通用结构,允许我嵌套函数、单元格值和常量的组合,以创建复合函数,如 Average
或 Sum
.>
在我的模型文件夹中,我有以下类可以将我的数据投射到:
公开课说明{公共操作[] 操作{ 获取;放;}}公开课操作{公共字符串类型{获取;放;}公共对象[] Args { 获取;放;}}公开课价值{公共字符串列名 { 获取;放;}公共 int 行 { 得到;放;}}
注意Operation
中的Args
是object[]
类型.
当我通过将这个 JSON 发布到它来调用我的 Web 应用程序时,C# 会自动将 JSON 解析为我的模型文件夹中定义的对象.假设我们使用了示例 1:
[HttpPost]public IHttpActionResult Foo(指令说明){foreach(指令中的操作操作.操作){开关(操作类型){案例存在":Console.WriteLine("存在");//工作良好//因为我们到了这里,所以期望 Args[0] 是类型 'Value'var value = (Value) op.Args[0];//InvalidCastException//EXIST 的逻辑案例添加"://ADD 的逻辑//...}}}
它可以很好地投射 Operation
,并且我正确地输出了 Type
.我还将 Args
作为 object[]
获取,其中包含一个单独的元素.但是如果我尝试将它转换为 Value
,它会拒绝正确转换.
在这一切之后我的问题是:实现我在这里尝试做的事情的最佳方法是什么?我在正确的轨道上吗?如果是这样,我的错误是什么?如果我以错误的方式解决这个问题,那么更好的做法是什么?请注意,由于我使用的是 Visual Studio 开箱即用的 Web 应用程序框架,因此我似乎无法访问对 JSON 进行反序列化的函数,因此我认为我无法构建自定义反序列化器.>
请参阅这个显示我将如何使用动态类型的小提琴.
public static void Main(){var json = @"{""操作"":{""type"": ""添加"",""参数"": [{""type"": ""添加"",""参数"": [{""columnName"": ""SomeColumnB"",行"":12},{""columnName"": ""SomeColumnC"",行"":18}]}]}}";动态数据 = JsonConvert.DeserializeObject(json);Console.WriteLine(data.operation.type.ToString());Console.WriteLine(data.operation.args[0].args[0].columnName.ToString());Console.WriteLine((int)data.operation.args[0].args[0].row);}
I am using Visual Studio's auto generated REST Web Application project structure to create a RESTful API that consumes a JSON input.
Without going into too much detail, I have attempted to define a JSON structure like these:
Example 1:
"operation": {
"type": "EXIST",
"args": [
{
"ColumnName": "SomeColumnA",
"Row": 2
}
]
}
Example 2:
"operation": {
"type": "ADD",
"args": [
{
"type": "ADD",
"args": [
{
"columnName": "SomeColumnB",
"row": 12
},
{
"columnName": "SomeColumnC",
"row": 18
}
]
},
20
]
}
operation
represents one of any number of basic database operations and the arguments for those operations. In my first example, the operation is EXIST
, which should check a database cell to see if a value exists or not. The args
for this operation is simply an object that contains the column and row information for the cell to check (I call this a Value
). In my second example, the function is ADD
, which should add two values together and return the sum. Here, the arguments are a constant of 20 and a nested ADD
function, which itself takes two Values
. So, in general, the args
array can take either primitive values, another nested operation
, or a pair of values that represents a cell to read the actual value from. The ultimate goal here is to create a general structure that would allow me to nest combinations of functions, cell values, and constants to create compound functions like Average
or Sum
.
In my Models folder, I have the following classes to cast my data to:
public class Instruction
{
public Operation[] Operations { get; set; }
}
public class Operation
{
public string Type { get; set; }
public object[] Args { get; set; }
}
public class Value
{
public string ColumnName { get; set; }
public int Row { get; set; }
}
Note that the Args
in Operation
is of type object[]
.
When I call my web application by POSTing this JSON to it, C# automatically parses the JSON into objects defined in my Models folder. Say we used Example 1:
[HttpPost]
public IHttpActionResult Foo(Instruction instruction)
{
foreach(Operation op in instruction.Operations) {
switch (op.Type) {
case "EXIST":
Console.WriteLine("exist"); // works fine
// since we got here, expect Args[0] to be type 'Value'
var value = (Value) op.Args[0]; // InvalidCastException
// logic for EXIST
case "ADD":
// logic for ADD
// ...
}
}
}
It's casting Operation
just fine, and I get Type
out correctly. I also get Args
as an object[]
with a lone element in it. But if I try to cast it to Value
, it refuses to cast properly.
My question after all of this is: what is the best way to achieve what it looks like I'm attempting to do here? Am I on the right track? If so, what is my error? If I'm going about this the wrong way, what is a better practice alternative? Note that since I'm using Visual Studio's out-of-the-box Web Application framework I don't seem to have access to the function that deseralizes the JSON, so I don't think I can build a custom deserializer.
See this fiddle that shows how I would use the dynamic type.
public static void Main()
{
var json = @"{""operation"": {
""type"": ""ADD"",
""args"": [
{
""type"": ""ADD"",
""args"": [
{
""columnName"": ""SomeColumnB"",
""row"": 12
},
{
""columnName"": ""SomeColumnC"",
""row"": 18
}
]
}
]
}}";
dynamic data = JsonConvert.DeserializeObject(json);
Console.WriteLine(data.operation.type.ToString());
Console.WriteLine(data.operation.args[0].args[0].columnName.ToString());
Console.WriteLine((int)data.operation.args[0].args[0].row);
}
这篇关于将对象从 JSON 数组转换为 C# 中的自定义类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!