2017-04-03 82 views
0

我正在使用Visual Studio的自动生成的REST Web应用程序项目结构来创建一个使用JSON输入的RESTful API。将JSON数组中的对象从C#中的自定义类转换为对象#

没有进入太多细节,我试图限定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; } 
} 

注意,在OperationArgsobject[]类型。

当我通过POST这个JSON调用我的web应用程序时,C#会自动将JSON解析为我的Models文件夹中定义的对象。假设我们用例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去分流的功能,所以我不认为我可以构建自定义的反序列化器。

+0

除非你试图顺应一些已经发布的JSON有效载荷的规格,为什么不首先定义类启动和使用的许多类到JSON预览工具之一?这样你就知道在反序列化过程中很可能没有任何问题。这与XML相同,我很懒,总是先创建类 – MickyD

+0

哪个JSON数组,你想投射?Example1与Example2不同 –

+0

如果将Args定义为'public Value [] Args {get; set; }'?还要看看C#中的动态类型。你可以在你的Operation模型中定义Args为'public dynamic Args {get; set;}'。从那里你可以使用'Args [0] .row'而不需要另一个模型。 – garethb

回答

2

看到这个小提琴,显示我将如何使用动态类型。

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); 
} 
+0

我不得不承认,我抽象了一些我的代码,试图专注于确切的问题;我编辑了我的问题,更准确地表示了代码的外观。基本上,我的JSON将有一些任意数量的'操作',每一个都会有所不同。最重要的是,对于像ADD这样的操作,可能的'Args'可以是'Operation','Value'或者原语。所以我想我必须做'尝试{var colName = op.args [0] .columnName; } catch {}'检查'Value',等等?它会工作,但我想知道是否有更好的答案。 – Fawfulcopter

+0

你可以检查args是一个json数组还是一个json对象。尽管如此,我还是不确定语法。编写一个函数来执行检查,以便测试任意数量的参数。 – garethb