使用 json 键存储值,这是一个好方法吗?

Ran*_*Guy 5 json

我正在编写一个rest api,我对json序列化很陌生。

我知道一个 json 对象由成对的 <key>:<value>.

我有一个对象“channels”,它包含多个通道对象,这些对象包含一个 id 和一些其他属性,如“x”、“y”和“z”。

在我们的团队中,我们发现了两种表示对象“通道”的方式,我看到人们实现的通常方式是这样的:

{
"channels":
    [
        {
            "id":0,
            "x":0,
            "y":0,
            "z":0
        },
        ...
    ]
}
Run Code Online (Sandbox Code Playgroud)

还有这个版本,它使用 id 作为键:

{
"channels":
    {
        "0":
        {
            "x":0,
            "y":0,
            "z":0
        },
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,第一个实现显式使用数组,而第二个实现依赖于<key>直接访问特定通道。

表示这个对象的最佳方式是什么?可以将键表示为值(如前一种情况的 id)吗?

现在只有两个通道(总是 id 0 和 1),但将来我们可能会添加更多。

Bri*_*ers 7

您应该更喜欢第一种方法,因为以这种方式使用 JSON 更容易、更直观。如果有人想使用您的 API,他们可能会创建模型类来反序列化。使用第一种方法,这很容易:

public class RootObject
{
    public List<Channel> channels { get; set; }
}

public class Channel
{
    public int id { get; set; }
    public int x { get; set; }
    public int y { get; set; }
    public int z { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

实际上,您可以直接获取 JSON 并将其转储到像http://json2csharp.com/这样的生成器工具中以获取这些类(这就是我在这里所做的)。

相比之下,使用第二种方法,JSON 中表示 ID 的键是动态的,生成器不会这样识别。所以你会得到这样的东西,需要手动更正:

public class RootObject
{
    public Channels channels { get; set; }
}

public class Channels
{
    public __invalid_type__0 __invalid_name__0 { get; set; }
}

public class __invalid_type__0
{
    public int x { get; set; }
    public int y { get; set; }
    public int z { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我见过一些人尝试像这样修复它,这将适用于您的单通道示例,但显然不会扩展:

public class RootObject
{
    public Channels channels { get; set; }
}

public class Channels
{
    [JsonProperty("0")]
    public Data Item0 { get; set; }
}

public class Data
{
    public int x { get; set; }
    public int y { get; set; }
    public int z { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

要使用动态键正确使用 JSON,这些类实际上需要如下所示:

public class RootObject
{
    public Dictionary<string, Channel> channels { get; set; }
}

public class Channel
{
    public int x { get; set; }
    public int y { get; set; }
    public int z { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然而,您需要在此处使用字典这一事实对于临时用户而言并不总是直观的。事实上,我已经忘记了“我如何处理 JSON 中的动态键?”这个问题的次数。在 StackOverflow上被问到。帮您的用户一个忙,不要让他们考虑。

除了反序列化 JSON 之外,第一个模型也更优越,因为该Channel对象包含有关通道的所有数据:idis 在对象本身内部。以这种方式传递和使用很容易。如果您需要进行密钥查找,将 a 转换List<Channel>为 a也很简单Dictionary<int, Channel>

var dict = rootObject.channels.ToDictionary(ch => ch.id);
Run Code Online (Sandbox Code Playgroud)

使用第二种方法,id它与通道数据的其余部分是分开的,所以如果你想将通道传递给一个需要两者的方法,你要么必须传递两个参数,要么创建一个新的模型类来将所有内容包装在一起。换句话说,使用起来更别扭。

最重要的是,我认为使用第二种方法根本没有真正的好处。跟着第一个走。