You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何反序列化带有Dictionary属性的[System.Serializable]结构体?

问题描述

我有一个标记了[System.Serializable]的结构体,初始代码如下:

[Serializable]
public struct User 
{
    public string name;
}

我想给它添加一个Dictionary<string, string>类型的experiments属性——因为这个属性的内容是后端动态生成的,而且键包含-,没法定义成另一个可序列化结构体。

但添加之后,experiments在反序列化时始终是null,我试过换成IDictionary类型也没用。修改后的结构体:

[Serializable]
public struct User 
{
    public string name;
    public Dictionary<string, string> experiments;
}

服务器返回的JSON格式确认如下:

{
    "name": "Bob",
    "experiments": {
        "experiment-3532": "control"
    }
}

我使用这个结构体的代码:

public IEnumerator GetUser(Action<User> callback, Action<string> errorCallback)
{
    string url = "https://myurl.com/myurl/"; // 模拟接口地址

    UnityWebRequest request = UnityWebRequest.Get(url);
    request.SetRequestHeader("Content-Type", "application/json");
    request.SetRequestHeader("Version", Application.version);

    yield return request.SendWebRequest();
    if (request.error == null)
        callback(JsonUtility.FromJson<User>(request.downloadHandler.text));
    else
        errorCallback("Uh oh! Network error");

    request.Dispose();
}
解决方案

Unity自带的JsonUtility不支持直接序列化/反序列化Dictionary类型,以下是几种可行的解决办法:

方案1:自定义可序列化字典类

实现一个继承自Dictionary并支持Unity序列化的类,借助ISerializationCallbackReceiver接口完成字典和List的双向转换:

[Serializable]
public class SerializableStringDictionary : Dictionary<string, string>, ISerializationCallbackReceiver
{
    [SerializeField]
    private List<string> keys = new List<string>();
    [SerializeField]
    private List<string> values = new List<string>();

    // 序列化前把字典内容转存到List
    public void OnBeforeSerialize()
    {
        keys.Clear();
        values.Clear();
        foreach (var pair in this)
        {
            keys.Add(pair.Key);
            values.Add(pair.Value);
        }
    }

    // 反序列化后从List恢复字典内容
    public void OnAfterDeserialize()
    {
        this.Clear();
        if (keys.Count != values.Count)
            throw new System.Exception($"字典键值数量不匹配:键数量{keys.Count},值数量{values.Count}");
        
        for (int i = 0; i < keys.Count; i++)
        {
            this[keys[i]] = values[i];
        }
    }
}

然后修改User结构体的属性类型:

[Serializable]
public struct User 
{
    public string name;
    public SerializableStringDictionary experiments;
}

方案2:替换为第三方JSON库

直接使用支持Dictionary的第三方JSON库,比如Newtonsoft.Json(Json.NET),不需要修改原结构体定义,直接替换反序列化代码即可:

// 需先通过Unity Package Manager安装Newtonsoft.Json包
if (request.error == null)
{
    User user = Newtonsoft.Json.JsonConvert.DeserializeObject<User>(request.downloadHandler.text);
    callback(user);
}

方案3:手动解析JSON

如果不想引入第三方库,可以用轻量级JSON解析工具(比如SimpleJSON)手动提取数据:

// 需导入SimpleJSON库
if (request.error == null)
{
    var json = JSON.Parse(request.downloadHandler.text);
    User user = new User();
    user.name = json["name"].Value;
    user.experiments = new Dictionary<string, string>();
    
    foreach (var kvp in json["experiments"].AsObject)
    {
        user.experiments.Add(kvp.Key, kvp.Value.Value);
    }
    
    callback(user);
}

内容的提问来源于stack exchange,提问作者kbunarjo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 14:30:52