首页 > 解决方案 > 如何在 Unity 中由用户定义从 JSON 获取哪个字段名称

问题描述

当我使用 JsonUtility 在我的类中通过变量名称指定字段名称时,我能够在 Unity 中读取 JSON。我想让我的脚本更通用,以便用户可以从多个 JSON 中定义要使用的字段名称,而不必使用相同的字段名称。

// call this function to get array of JsonEntry objects
public static T[] FromJson<T>(string json)
{
        return JsonUtility.FromJson<JsonEntries<T>>(json).Entries;
}

我正在使用这个类

[Serializable]
public class JsonEntries<T>
{
    public T[] Entries;
}

[Serializable]
public class JsonEntry 
{
    // field names from one JSON example
    public string USULAN_ID; 
    public string USULAN_LAT;
    public string USULAN_LONG;
    public string USULAN_URGENSI;

    //TODO user defined filed names
}

如果我在 Unity 中使用 JsonUtility 事先不知道字段名称,是否可以让用户定义要使用的字段名称?

标签: c#jsonunity3d

解决方案


不使用JsonUtility,不!

使用 Unity JsonUtility,您必须事先知道字段名称,并实现表示 JSON 结构的类,包括精确匹配的字段名称。它也仅限于某些类型:

API 支持任何具有该属性的MonoBehaviour-subclass、ScriptableObject-subclass 或普通类/结构。[Serializable]你传入的对象会被送入标准的 Unity 序列化器进行处理,因此与 Inspector 中的规则和限制相同;只有字段被序列化,类型如Dictionary<>; 不支持

目前不支持将其他类型直接传递给 API,例如原始类型或数组。现在,您需要将此类类型包装在某种类或结构中。


假设您只需要一个级别并且 JSON 看起来像例如

{
    "USULAN_ID":"some id", 
    "USULAN_LAT":"some lat",
    "USULAN_LONG":"some long",
    "USULAN_URGENSI":"some urgensi"
}

其中字段名称和计数可能会动态更改,您可以使用SimpleJSON. 为此,只需将 的内容复制SimpleJSON.cs到项目中相应命名的新文件中,然后添加using SimpleJSON;到要使用它的脚本中。

在场景中,我会简单地使用 aDropdown让用户决定使用哪个字段

using SimpleJSON;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class DropDownController : MonoBehaviour
{
    [Header("Components References")]
    public Dropdown dropdown;

    [Header("Input")]
    // Where ever you get the json data from
    public string JsonString = "{\"USULAN_ID\":\"some id\", \"USULAN_LAT\":\"some lat\", \"USULAN_LONG\":\"some long\", \"USULAN_URGENSI\":\"some urgensi\"}";

    [Header("Output")]
    public string currentlySelectedKey;
    public string currentlySelectedValue;
    public Text selectedValueText;

    private Dictionary<string, string> entries = new Dictionary<string, string>();

    private void Awake()
    {
        // get the component
        if (!dropdown) dropdown = GetComponent<Dropdown>();

        // register a callback 
        dropdown.onValueChanged.AddListener(HandleValueChanged);

        // where ever you need to call this method
        UpdateOptions(JsonString);
    }

    public void UpdateOptions(string jsonString)
    {
        // parse the string to a JSONNode
        var json = JSON.Parse(jsonString);

        // unfortunately SimpleJson simply returns null
        // and doesn't throw any exceptions so you have to do it on your own
        if(json == null)
        {
            Debug.LogFormat(this, "Oh no! Something went wrong! Can't parse json: {0}", jsonString);
            return;
        }

        // for the case this is called multiple times
        // reset the lists and dictionaries
        dropdown.options.Clear();
        entries.Clear();

        //optional add a default field
        entries.Add("Please select a field", "no field selected!");
        dropdown.options.Add(new Dropdown.OptionData("Please select a field"));

        // JSONNode implements an Enumerator letting
        // us simply iterate through all first level entries
        foreach (var field in json)
        {
            // simply assume string keys and string values
            // might brake if the provided json has another structure
            // I'll skip the null checks here
            var key = field.key;
            var value = field.value;

            entries.Add(key, value);
            dropdown.options.Add(new Dropdown.OptionData(key));
        }

        // set default
        dropdown.value = 0;
        HandleValueChanged(0);
    }

    private void HandleValueChanged(int newValue)
    {
        currentlySelectedKey = dropdown.options[newValue].text;
        currentlySelectedValue = entries[currentlySelectedKey];

        // optional visual feedback for the user
        selectedValueText.text = currentlySelectedValue;
        // optional color feedback for not yet selected
        selectedValueText.color = newValue == 0 ? Color.red : Color.black;
    }
}

在此处输入图像描述


注意:用Unity 2019.1;测试 由于 UI 已更改,因此Dropdown可能会有所不同。2019.2


推荐阅读