【问题标题】:parsing json file in unity [duplicate]统一解析json文件[重复]
【发布时间】:2021-07-14 15:30:30
【问题描述】:

我无法在 Unity 中解析 JSON。这是 JSON 文件:

{
  "play_classic": [
    { "english": "PLAY CLASSIC" },
    { "spanish": "JUEGO CLÁSICO" },
    { "portuguese": "JUEGO CLÁSICO" },
    { "russian": "IGRAT' V KLASSICHESKUYU" }
  ]
}

结构和代码如下所示:

[System.Serializable]
    class Root
    {
        public List<PlayClassicData> play_classic { get; set; }  
    }



[System.Serializable]
    class PlayClassicData
    {

        public string english { get; set; }

        public string spanish { get; set; }

        public string portuguese { get; set; }

        public string russian { get; set; }
    }

实现如下所示:

ParseJson类:

 public void Deserialize()
        {
string path = Application.dataPath + "path...";
        
        using (StreamReader r = new StreamReader(path))
        {
            string json = r.ReadToEnd();
            Root classic = JsonUtility.FromJson<Root>(json);
            //Root classic = JsonConvert.DeserializeObject<Root>(json);
            Debug.Log("english:" + classic.play_classic[0].english);
            Debug.Log("spanish:" + classic.play_classic[0].spanish);
       }
}

代码抛出错误:

NullReferenceException: Object reference not set to an instance of an object
Assets.Scripts.Infastructure.PARSER.ParseJson.Deserialize () (at Assets/Scripts/Infastructure/PARSER/ParseJson.cs:23)

【问题讨论】:

  • 我没有添加整个代码。
  • 您可能不想在这里使用内置的JsonUtility,而是使用例如Newtonsoft .NET JSON -> 它支持(de)serialization of Dictionary,因此您实际上可以拥有public Dictionary&lt;string, string&gt; play_classic = new Dictionary&lt;string, string&gt;();,并且可以轻松地在您的JSON文件中动态扩展它...
  • 另外 JsonUtility 不支持属性 .. 你想通过删除所有 {get; set} 来使用字段

标签: c# json unity3d


【解决方案1】:

这里有两个问题。

  1. 错误的Root。应该是public List&lt;PlayClassicData&gt; play_classic { get; set; }
  2. 索引。 classic._playClassicData[0].spanish 为空。这是具有西班牙语值的第二个元素:classic._playClassicData[1].spanish);

固定Root:

class Root
{
   public List<PlayClassicData> play_classic { get; set; } 
}

演示:

var json = File.ReadAllText("example1.json");
var o = JsonSerializer.Deserialize<Root>(json);
Console.WriteLine(o.play_classic[0].english);
Console.WriteLine(o.play_classic[1].spanish);

打印出来:

PLAY CLASSIC
JUEGO CLÁSICO

我使用了System.Json.Text.JsonSerializer,但使用JsonConvert.DeserializeObject&lt;Root&gt;(json); 结果是一样的。

【讨论】:

  • 我改了还是一样的错误
  • 一个。 json 是否有预期的文本?湾。 JsonUtility.FromJson 这就是您的空异常所在的位置。使用JsonConvert.DeserializeObject&lt;Root&gt;(json)
  • 它只适用于 JsonConvert.DeserializeObject...这是统一的
  • 请注意 System.Json.Text.JsonSerializer 在使用 .Net Framework 4.x 的 Unity 中不可用,Unity 的内置 JsonUtility 并且通常序列化程序不支持属性。您想通过删除 {get; set;} 将它们转换为字段
【解决方案2】:

我将假设 Json 是多语言翻译的表示。并且可以在返回中翻译多个句子/标签。
而且您不希望为play_classicplay_hard 提供一个具有相同语言属性的类。特别是如果添加一种语言会迫使您在前端和每个类中添加一个属性。

{
    "play_classic": [
        { "english": "PLAY CLASSIC" },
        { "spanish": "JUEGO CLÁSICO" },
        { "portuguese": "JUEGO CLÁSICO" },
        { "russian": "IGRAT' V KLASSICHESKUYU" }
    ],
    "play": [
        { "english": "PLAY" },
        { "spanish": "JUEGO" },
        { "portuguese": "JUEGO" },
        { "russian": "IGRAT'" }
    ],
    "classic": [
        { "english": "CLASSIC" },
        { "spanish": "CLÁSICO" },
        { "portuguese": "CLÁSICO" },
        { "russian": "KLASSICHESKUYU" }
    ]
}

我将选择Dictionary&lt;string, List&lt;Dictionary&lt;string, string&gt;&gt;&gt; 作为目标对象。并且会将内部列表弄平,例如:Dictionary&lt;string, Dictionary&lt;string, string&gt;&gt;.
注意:由于内置的​​JsonUtility 不支持字典,因此您必须另外将Newtonsoft .Net JSON 安装/导入到您的项目中。 derHugo评论,用户:7111561

var resultRaw = JsonConvert.DeserializeObject<Dictionary<string, List<Dictionary<string, string>>>>(input);

var resultFlattern = resultRaw.ToDictionary(
                                x => x.Key, 
                                x=> x.Value.SelectMany(trd=> trd)
                                .ToDictionary(kvp=> kvp.Key, kvp=> kvp.Value)
                            );

用法:给定按钮 play_classic 和语言“葡萄牙语”
直接访问将非常简单 resultFlattern[buttonName][language]

var buttonName="play_classic"; var language= "portuguese";

if(resultFlattern.TryGetValue(buttonName, out Dictionary<string, string>  allTrads))
{
    if(allTrads.TryGetValue(language, out string traduction)){
        Console.WriteLine($"Traduction for button [{buttonName}] in [{language}] is : [{traduction}]") ;
    }
    else{
        Console.WriteLine($"Cant find tanslation for button : [{buttonName}] in [{language}]") ;
    }
}
else{ 
    Console.WriteLine($"Cant find tanslation for button : [{buttonName}]");
}

演示:https://dotnetfiddle.net/FcxtUp

我将把它包装成一个只加载一次所有翻译的好帮手。并给出给定语言和按钮/标签的翻译。当没有找到翻译时,我还将使用默认返回标签名称来防火。

如果语言不是一件容易的事情,你可以再一次改变结果,只在Dictionary&lt;string, string&gt; 中保留一份翻译。标签名称/翻译

【讨论】:

  • 很好的例子和解决方案。
  • 请注意,为此您必须另外安装/导入Newtonsoft .Net JSON 到您的项目中,因为内置的JsonUtility 不支持Dictionary ;) .. 一般请注意,为此虽然.CSV 的使用更方便;)
  • @derHugo,在 OP 代码中有一个 JsonConvert.DeserializeObject&lt;Root&gt;(json);,并且 Op 有一条评论,例如“它只适用于 JsonConvert.DeserializeObject&lt;Root&gt;...这是统一的”。我认为它是可用的。
  • 将您的评论添加到答案中,并注明出处。
  • @Self 哦,没注意到。我的立场已得到纠正;)似乎 OP 已经这样做了(或者 Unity 在较新版本中默认导入该包)
【解决方案3】:

您的 Json 与您的数据不匹配

public PlayClassicData[] _playClassicData { get; set; } 

应该是:

public List<PlayClassic> play_classic { get; set; }

所以classic._playClassicData 是探测null

编辑:

正如 derHugo 指出的那样:

Unity 的内置 JsonUtility 不支持属性。您想通过删除所有 {get; set;} 来使用字段

应该是:

public List<PlayClassic> play_classic;

【讨论】:

  • 我添加了列表而不是数组相同的错误没有任何改变。
  • 不仅列表和数组不同,而且属性上的名字和json中的名字不匹配
  • 我再次更改了列表的名称同样的错误。
  • Unity 的内置 JsonUtility 不支持属性。您想通过删除所有 {get; set;} 来使用字段
猜你喜欢
  • 2023-04-02
  • 2012-02-14
  • 2013-02-28
  • 1970-01-01
  • 2020-09-30
  • 2015-08-10
  • 2016-08-13
  • 2017-07-31
  • 1970-01-01
相关资源
最近更新 更多