将对象从 JSON 数组转换为 C# 中的自定义类 [英] Casting objects from JSON array to custom classes in C#

查看:57
本文介绍了将对象从 JSON 数组转换为 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 或代表要从中读取实际值的单元格的一对值.这里的最终目标是创建一个通用结构,允许我嵌套函数、单元格值和常量的组合,以创建复合函数,如 AverageSum.>

在我的模型文件夹中,我有以下类可以将我的数据投射到:

公开课说明{公共操作[] 操作{ 获取;放;}}公开课操作{公共字符串类型{获取;放;}公共对象[] Args { 获取;放;}}公开课价值{公共字符串列名 { 获取;放;}公共 int 行 { 得到;放;}}

注意Operation中的Argsobject[]类型.

当我通过将这个 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.

Fiddle

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆