【问题标题】:How do I get and return a key value from a complex json object?如何从复杂的 json 对象中获取和返回键值?
【发布时间】:2019-12-12 15:56:32
【问题描述】:

我有一个不和谐的机器人,它可以从 JSON 文件中获取密钥并根据用户输入的命令返回值。我希望能够访问复杂的 JSON 键(如“charQuote”)并返回关联值(即“此处的视频游戏角色引用”)。

{
"characterKey": 
{
"charName":"Video Game character name here",
"charQuote": "Video Game character quote here", 
"charImageURL": "Video Game character image url here"
}

//I omitted 11 other complex objects that are similar to this one
}

其他答案如:

How do I deserialize a complex JSON object in C# .NET?

How to get Key from nested object with a Json Object and return in array?

how to get the key from json object and convert into an array?

...反序列化并将复杂对象和/或键作为数组返回。但我想从一个复杂对象返回一个键值。

在这里,我有一个用简单的 JSON 对象管理单独的 JSON 文件的类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.IO;

namespace discordbot.Modules
{
    class Utilities
    {
        private static Dictionary<string, string> alerts;
        private const string File_Path = "json files/alerts.json";

        static Utilities()
        {
            string json = File.ReadAllText(File_Path);
            var data = JsonConvert.DeserializeObject<dynamic>(json);
            alerts = data.ToObject<Dictionary<string, string>>();          
        }

        public static string GetAlert(string key) //"hello" == key
        {
            if (alerts.ContainsKey(key))
                return alerts[key]; //returns "Hello World" which is the value
            return "";
        }

这个类从输入的键返回值。将使用此类的示例异步任务方法是:

[Command("test")]
        public async Task HelloWorldAsync(string hello = "hello")
        {
            await ReplyAsync(Utilities.GetAlert(hello));
        }

这是与包含复杂对象的 JSON 文件相关联的类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;

namespace discordbot.Modules
{
    public static class CharacterUtilities 
    {

        //private static List<Dictionary<string, string>> QuoteAndPicture = new List<Dictionary<string, string>>();
        private static Dictionary<string, string> QuoteAndPicture = new Dictionary<string, string>();

        private const string File_Path = "json files/quotesandimages.json";

        static CharacterUtilities()
        {
            if(!File.Exists(File_Path))
            {
                File.WriteAllText(File_Path, "");
            }

            string json = File.ReadAllText(File_Path); 
            var data = JsonConvert.DeserializeObject<dynamic>(json);
            QuoteAndPicture = data.ToObject<Dictionary<string, string>>();

        }

        public static string GetQuoteImageName(string key) 
        {                        
            if (QuoteAndPicture.ContainsKey(key)))
                return QuoteAndPicture[key];
            return "";
        }

调用GetQuoteImageName的异步方法

[Command("ex")] [RequireOwner]
        public async Task CharacterAsync(string characterContext)
        {                   
            await ReplyAsync(CharacterUtilities.GetQuoteImageName(characterContext)); 
        }

现在,如果我调用 GetQuoteImageName 方法,我会收到错误:The type initializer for 'discordbot.Modules.CharacterUtilities' threw an exception.

所以我想知道是否有类似的方法从复杂对象返回奇异值而不是所有复杂值,类似于上面的第一个类。

【问题讨论】:

    标签: c# json discord


    【解决方案1】:

    这将根据keysToSearchThrough 搜索json。

            var data = JsonConvert.DeserializeObject<dynamic>(jsonString);
            // The keys you have to search through.
            string[] keysToSearchThrough = new string[] { "characterKey", "charName" };
    
            string result = string.Empty;
    
            // The current data it is travesing through
            Dictionary<string, dynamic> currTraversedData = data.ToObject<Dictionary<string, dynamic>>();
    
            for (int i = 0; i < keysToSearchThrough.Length; ++i) {
    
                if (currTraversedData.ContainsKey(keysToSearchThrough[i])) {
                    // Get the value if the key current exists
                    dynamic currTravesedDataValue = currTraversedData[keysToSearchThrough[i]];
    
                    // Check if this 'currTravesedDataValue' can be converted to a 'Dictionary<string, dynamic>'
                    if (IsStringDynamicDictionary(currTravesedDataValue)) {
                        // There is still more to travese through
                        currTraversedData = currTravesedDataValue.ToObject<Dictionary<string, dynamic>>();
                    } else {
                        // There is no more to travese through. (This is the result)
                        result = currTravesedDataValue.ToString();
    
                        // TODO: Some error checking in the event that we reached the result early, even though we still have more keys to travase through
                        break;
                    }
    
                } else {
                    // One of the keys to search through was probably invalid.
                }
            }
    
            // ...
    
            bool IsStringDynamicDictionary(dynamic input) {
                try {
                    input.ToObject<Dictionary<string, dynamic>>();
                    return true;
                } catch (Exception) {
                    return false;
                }
            }
    

    这最初会将 json 数据转换为 Dictionary&lt;string, dynamic&gt;。

    我们之所以有dynamic 是因为Value 在任何给定时间点都可以是string 或Dictionary&lt;string, string&gt;。

    然后我们循环遍历keysToSearchThrough,检查当前遍历的字典中是否存在键。

    如果key确实存在,则检查当前遍历字典的Value是否为Dictionary&lt;string, dynamic&gt;类型。

    如果是这样,那意味着我们将需要遍历更多内容。
    如果没有,这意味着我们可能已经走到了尽头。

    示例
    在"charName":"Character name" 中,Value 是String 的一种类型。这标志着我们走到了尽头。
    在"charName": "Character name", "charQuote": "Character Quote" 中,Value 将是Dictionary&lt;string, dynamic&gt; 的一种类型。这标志着我们仍然可以遍历数据。

    如果不够明显,主要的缺点是这段代码看起来真的很乱。

    【讨论】:

    • 既然我将有 11 个其他复杂对象,我不是必须为所有这些对象创建 11 个类吗?
    • @UchennaOnuigbo 对不起,我最初没有明白你的意思。我编辑了我的答案以适合您的问题。希望对你有帮助
    猜你喜欢
    • 2016-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-14
    相关资源
    最近更新 更多