【问题标题】:Casting objects from JSON array to custom classes in C#将对象从 JSON 数组转换为 C# 中的自定义类
【发布时间】:2017-04-03 02:18:32
【问题描述】:

我正在使用 Visual Studio 的自动生成的 REST Web 应用程序项目结构来创建一个使用 JSON 输入的 RESTful API。

没有过多的细节,我尝试定义一个像这样的 JSON 结构:

示例 1:

"operation": {
    "type": "EXIST",
    "args": [
      {
        "ColumnName": "SomeColumnA",
        "Row": 2
      }
    ]
  }

示例 2:

"operation": {
    "type": "ADD", 
    "args": [
      {
        "type": "ADD",
        "args": [
          {
            "columnName": "SomeColumnB",
            "row": 12
          },
          {
            "columnName": "SomeColumnC",
            "row": 18
          }
        ]
      },
      20
    ]
  }

operation 表示任意数量的基本数据库操作之一以及这些操作的参数。在我的第一个示例中,操作是EXIST,它应该检查数据库单元以查看值是否存在。此操作的args 只是一个对象,其中包含要检查的单元格的列和行信息(我称之为Value)。在我的第二个示例中,函数是ADD,它应该将两个值相加并返回总和。这里,参数是一个常量 20 和一个嵌套的 ADD 函数,它本身需要两个 Values。因此,一般来说,args 数组可以采用原始值、另一个嵌套的 operation 或一对表示要从中读取实际值的单元格的值。这里的最终目标是创建一个通用结构,允许我嵌套函数、单元格值和常量的组合,以创建像 AverageSum 这样的复合函数。

在我的模型文件夹中,我有以下类可以将我的数据转换为:

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; }
}

注意Operation 中的Argsobject[] 类型。

当我通过 POST 这个 JSON 来调用我的 Web 应用程序时,C# 会自动将 JSON 解析为我的模型文件夹中定义的对象。假设我们使用了示例 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
            // ...
        }
    }
}

它正在投射Operation 就好了,我正确地得到了Type。我还得到Args 作为object[],其中有一个单独的元素。但如果我尝试将其转换为 Value,它会拒绝正确转换。

在这一切之后,我的问题是:实现我在这里尝试做的最好方法是什么?我在正确的轨道上吗?如果是这样,我的错误是什么?如果我以错误的方式解决这个问题,那么更好的做法是什么?请注意,由于我使用的是 Visual Studio 的开箱即用 Web 应用程序框架,我似乎无法访问反序列化 JSON 的函数,因此我认为我无法构建自定义反序列化器。

【问题讨论】:

  • 除非您尝试遵循一些已经发布的 JSON 有效负载规范,否则为什么不首先定义您的类并使用众多类到 JSON 预览工具之一呢?这样你就知道在反序列化期间很可能不会有任何问题。 XML也是一样,我比较懒,总是先创建类
  • 要转换哪个 JSON 数组?Example1 与 Example2 不同
  • 如果将 Args 定义为 public Value[] Args{get;set;} 会发生什么?还要查看 C# 中的动态类型。您可以在 Operation 模型中将 Args 定义为 public dynamic Args{get;set;}。从那里您可以直接使用Args[0].row,而无需其他模型。
  • @garethb - 我无法将类型设置为 Value[],因为该数组可能包含 intstringdoubleboolValue 或 @ 987654353@。我无法提前知道它是哪种类型,我只能在运行时检查它并执行正确的转换。
  • @Fawfulcopter 在这种情况下,我会将 Args 定义为动态的。

标签: c# json rest


【解决方案1】:

看看这个小提琴,它展示了我将如何使用动态类型。

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 将有一些任意数量的 Operations 并且每个都不同。最重要的是,对于像ADD 这样的操作,可能的Args 可以是OperationValue 或原语。所以我想我必须做try { var colName = op.args[0].columnName; } catch {} 来检查Value,等等?它会起作用,但我想知道是否有更好的答案。
  • 可以检查args是json数组还是json对象。不过,我不确定我脑海中的语法。编写一个函数来进行检查,以便您可以测试任意数量的参数。
猜你喜欢
  • 2023-03-11
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 2021-07-02
  • 1970-01-01
  • 2017-03-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多