C# 如何使用字典解析这个JSON?

C# 如何使用字典解析这个JSON?,c#,json,json.net,steam,steam-web-api,C#,Json,Json.net,Steam,Steam Web Api,我正在制作一个需要解析JSON响应的程序。回复中的大部分数据都是无用的,但我需要用它做一些事情 能够从rgInventory部分检索id的搜索,然后获得相应的classid 获取具有此classid的对象的market\u名称 JSON响应(代码片段,以该格式继续): 完整JSON响应: 我认为,由于库存中每个项目的标识符不断变化(即从469449975_0到619638799_0),我必须将其反序列化到字典中 以下是我迄今为止的代码: namespace SteamTrade { pu

我正在制作一个需要解析JSON响应的程序。回复中的大部分数据都是无用的,但我需要用它做一些事情

  • 能够从
    rgInventory
    部分检索
    id
    的搜索,然后获得相应的
    classid
  • 获取具有此
    classid的对象的
    market\u名称
  • JSON响应(代码片段,以该格式继续):

    完整JSON响应:

    我认为,由于库存中每个项目的标识符不断变化(即从
    469449975_0
    619638799_0
    ),我必须将其反序列化到字典中

    以下是我迄今为止的代码:

    namespace SteamTrade
    {
        public class CSGOInventory
        {
            public static CSGOInventory FetchInventory(string steamId)
            {
                WebClient client = new WebClient();
                var url = "http://steamcommunity.com/profiles/" + steamId + "/inventory/json/730/2/";
                string response =  client.DownloadString(url);
                Dictionary<string, Item> result = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, Item>>(response);
                return new CSGOInventory(result);
            }
    
            public Item[] Items { get; set; }
            public bool IsPrivate { get; private set; }
            public bool IsGood { get; private set; }
    
            protected CSGOInventory(Dictionary<string, Item> apiInventory)
            {
                for (int i = 0; i < apiInventory.Count; i++)
                {
                    Items[i] = apiInventory.Values.ElementAt(i);
                }
            }
    
            /*public Item GetItem(int id)
            {
                return (Items == null ? null : Items.FirstOrDefault(item => item.instanceid == id));
            }
    
            public List<Item> GetItemsByDefindex(int defindex)
            {
                return Items.Where(item => item.def_index == defindex).ToList();
            }*/
    
            public class Item
            {
                public string AppId = "730";
                public string ContextId = "2";
    
                [JsonProperty("instanceid")]
                public string instanceid { get; set; }
    
                [JsonProperty("market_name")]
                public string market_name { get; set; }
    
                [JsonProperty("def_index")]
                public string def_index { get; set; }
    
            }
    
            protected class InventoryResult
            {
                public Item[] items { get; set; }
            }
    
            protected class InventoryResponse
            {
                public InventoryResult result;
            }
    
        }
    }
    

    这将返回一个错误,说明序列中没有项目。

    您正试图将其反序列化到
    字典中,这显然失败,因为您有无法反序列化到
    项目的元素,并且在第一个元素上失败,即
    成功:true

    你有两种方法可以继续

  • var result=(动态)Newtonsoft.Json.JsonConvert.DeserializeObject(响应)

    在这种情况下,可以将结果作为动态对象进行处理

  • 定义并使用与您尝试反序列化的json格式相对应的类


  • 您真正要做的是查询JSON。为此,可以使用DixonD建议的动态对象对其进行反序列化,然后遍历动态对象以找到所需的信息


    另一个更简单、更简洁的解决方案是使用类似于XPath for JSON的库来查询JSON。有一个例子可以说明如何做这样的事情。

    根据,您在问题中发布的JSON无效。但是,JSON在上是可以的,所以让我们继续吧

    您需要的信息可以建模为包含两个字典的类:

    public class rgInventoryItem
    {
        public string id { get; set; }
        public string classid { get; set; }
    }
    
    public class rgDescription
    {
        public string classid { get; set; }
        public string market_name { get; set; }
    }
    
    public class InventoryResponse
    {
        public Dictionary<string, rgInventoryItem> rgInventory { get; set; }
    
        public Dictionary<string, rgDescription> rgDescriptions { get; set; }
    }
    
    要从classid创建市场名称,可以执行以下操作

        var classidToDescription = response.rgDescriptions.ToLookup(pair => pair.Value.classid);
    
    这将找到给定
    classid
    的所有
    rgDescription

    如果您确定给定的
    classid
    只有一个
    rgDescription
    ,则可以执行以下操作:

        var classidToDescriptionDictionary = response.rgDescriptions.ToDictionary(pair => pair.Value.classid);
    
    请注意,如果多个描述具有相同的类id,则这将抛出一个带有消息“已添加具有相同密钥的项”的
    ArgumentException

    更新

    要从
    market\u name
    转到
    id
    ,您需要反转字典并创建反向查找表。因此:

  • 如果您需要回复中的所有市场名称,请执行以下操作:

        var marketNames = response.rgDescriptions.Values.Select(d => d.market_name);
    
        var ids = response.rgInventory.Keys;
    
  • 如果您需要响应中的所有ID,请执行以下操作:

        var marketNames = response.rgDescriptions.Values.Select(d => d.market_name);
    
        var ids = response.rgInventory.Keys;
    
  • 要从
    market\u name
    映射到
    id
    ,首先创建反向查找:

        var classIdToId = response.rgInventory.ToLookup(pair => pair.Value.classid, pair => pair.Key);
        var marketNameToId = response.rgDescriptions
            .SelectMany(pair => classIdToId[pair.Value.classid].Select(id => new KeyValuePair<string, string>(pair.Value.market_name, id)))
            .ToLookup(pair => pair.Key, pair => pair.Value);
    
    要获取引用给定市场名称的第一个id,请执行以下操作:

        var idsForMarket = marketNameToId[name].ToList();
    
        var firstIdForMarket = marketNameToId[name].FirstOrDefault();
    
  • 更新2

    以下是您的类的修改版本:

    public class rgInventoryItem
    {
        public string id { get; set; }
        public string classid { get; set; }
    }
    
    public class rgDescription
    {
        public string classid { get; set; }
        public string market_name { get; set; }
    }
    
    public class CSGOInventory
    {
        public static CSGOInventory FetchInventory(string steamId)
        {
            var url = "http://steamcommunity.com/profiles/" + steamId + "/inventory/json/730/2/";
            return FetchInventoryFromUrl(new Uri(url));
        }
    
        public static CSGOInventory FetchInventoryFromUrl(Uri url)
        {
            using (WebClient client = new WebClient())
            {
                string response = client.DownloadString(url);
                var inventory = JsonConvert.DeserializeObject<InventoryResponse>(response);
                return new CSGOInventory(inventory);
            }
        }
    
        readonly InventoryResponse inventory;
        readonly ILookup<string, string> classIdToId;
        readonly ILookup<string, string> marketNameToId;
    
        CSGOInventory(InventoryResponse inventory)
        {
            if (inventory == null)
                throw new ArgumentNullException();
    
            this.inventory = inventory;
    
            this.classIdToId = inventory.rgInventory.ToLookup(pair => pair.Value.classid, pair => pair.Key);
            this.marketNameToId = inventory.rgDescriptions
                .SelectMany(pair => classIdToId[pair.Value.classid].Select(id => new KeyValuePair<string, string>(pair.Value.market_name, id)))
                .ToLookup(pair => pair.Key, pair => pair.Value);
        }
    
    
        public IDictionary<string, rgInventoryItem> InventoryItems { get { return this.inventory == null ? null : this.inventory.rgInventory; } }
    
        public IDictionary<string, rgDescription> InventoryDescriptions { get { return this.inventory == null ? null : this.inventory.rgDescriptions; } }
    
        public IEnumerable<string> MarketNames { get { return InventoryDescriptions == null ? null : InventoryDescriptions.Values.Select(d => d.market_name); } }
    
        public IEnumerable<string> InventoryIds { get { return InventoryItems == null ? null : InventoryItems.Keys; } }
    
        public string getInstanceIdFromMarketName(string name)
        {
            return marketNameToId[name].FirstOrDefault();
        }
    
        public IEnumerable<string> getInstanceIdsFromMarketName(string name)
        {
            return marketNameToId[name];
        }
    
        class InventoryResponse
        {
            public Dictionary<string, rgInventoryItem> rgInventory { get; set; }
    
            public Dictionary<string, rgDescription> rgDescriptions { get; set; }
        }
    }
    
    给出输出

    Market SG 553 | Army Sheen (Factory New)                 : id 1482735510
    Market Offer | Music Kit | Noisia, Sharpened             : id 1468698711
    Market Offer | Sticker | Bomb Squad (Foil)               : id 1468698710
    Market Offer | Sticker | Dinked                          : id 1468698709
    Market Offer | Sticker | Kawaii Killer CT                : id 1468698708
    Market Operation Breakout Weapon Case                    : id 1462270322
    Market Operation Vanguard Weapon Case                    : id 1459818809
    Market M4A4 | Howl (Minimal Wear)                        : id 1450750270
    Market Operation Phoenix Weapon Case                     : id 1391297747
    Market Negev | Army Sheen (Minimal Wear)                 : id 1370560151
    Market Huntsman Weapon Case                              : id 1305163655
    Market Tec-9 | Army Mesh (Minimal Wear)                  : id 1304896559
    Market Galil AR | Cerberus (Well-Worn)                   : id 1214784536
    Market StatTrakT Tec-9 | Sandstorm (Field-Tested)        : id 1201208194
    Market G3SG1 | Contractor (Field-Tested)                 : id 1189828757
    Market Campaign Vanguard                                 : id 1103736871
    Market Campaign Weapons Specialist                       : id 1103736870
    Market Operation Vanguard Challenge Coin                 : id 1103736869
    Market StatTrakT XM1014 | Red Python (Field-Tested)      : id 957595359
    Market StatTrakT CZ75-Auto | Hexane (Field-Tested)       : id 814442137
    Market Negev | Army Sheen (Factory New)                  : id 623936007
    Market SSG 08 | Sand Dune (Well-Worn)                    : id 616381102
    Market Silver Operation Breakout Coin                    : id 612997861
    Market UMP-45 | Scorched (Field-Tested)                  : id 603041123
    

    假设我使用您建议的第一种方法,那么我如何继续获得所需的功能?(在我的帖子顶部声明)既然有了市场名称,我就可以让classid有效地反向操作?你是说你想知道我是如何创建数据模型的,如何使用字段
    rgInventory
    ,或者如何使用
    response.rgDescriptions.ToLookup
    的返回值?我这方面的问题很糟糕。我需要创建一个方法,该方法可以从market_Names获取rgInventory部分中的“id”。如果您想从
    market_name
    转到
    id
    ,那么?@JedBoffey-更新答案。这就是你需要的吗?
    public class rgInventoryItem
    {
        public string id { get; set; }
        public string classid { get; set; }
    }
    
    public class rgDescription
    {
        public string classid { get; set; }
        public string market_name { get; set; }
    }
    
    public class CSGOInventory
    {
        public static CSGOInventory FetchInventory(string steamId)
        {
            var url = "http://steamcommunity.com/profiles/" + steamId + "/inventory/json/730/2/";
            return FetchInventoryFromUrl(new Uri(url));
        }
    
        public static CSGOInventory FetchInventoryFromUrl(Uri url)
        {
            using (WebClient client = new WebClient())
            {
                string response = client.DownloadString(url);
                var inventory = JsonConvert.DeserializeObject<InventoryResponse>(response);
                return new CSGOInventory(inventory);
            }
        }
    
        readonly InventoryResponse inventory;
        readonly ILookup<string, string> classIdToId;
        readonly ILookup<string, string> marketNameToId;
    
        CSGOInventory(InventoryResponse inventory)
        {
            if (inventory == null)
                throw new ArgumentNullException();
    
            this.inventory = inventory;
    
            this.classIdToId = inventory.rgInventory.ToLookup(pair => pair.Value.classid, pair => pair.Key);
            this.marketNameToId = inventory.rgDescriptions
                .SelectMany(pair => classIdToId[pair.Value.classid].Select(id => new KeyValuePair<string, string>(pair.Value.market_name, id)))
                .ToLookup(pair => pair.Key, pair => pair.Value);
        }
    
    
        public IDictionary<string, rgInventoryItem> InventoryItems { get { return this.inventory == null ? null : this.inventory.rgInventory; } }
    
        public IDictionary<string, rgDescription> InventoryDescriptions { get { return this.inventory == null ? null : this.inventory.rgDescriptions; } }
    
        public IEnumerable<string> MarketNames { get { return InventoryDescriptions == null ? null : InventoryDescriptions.Values.Select(d => d.market_name); } }
    
        public IEnumerable<string> InventoryIds { get { return InventoryItems == null ? null : InventoryItems.Keys; } }
    
        public string getInstanceIdFromMarketName(string name)
        {
            return marketNameToId[name].FirstOrDefault();
        }
    
        public IEnumerable<string> getInstanceIdsFromMarketName(string name)
        {
            return marketNameToId[name];
        }
    
        class InventoryResponse
        {
            public Dictionary<string, rgInventoryItem> rgInventory { get; set; }
    
            public Dictionary<string, rgDescription> rgDescriptions { get; set; }
        }
    }
    
    public static class TestClass
    {
        public static void Test()
        {
            //string url = @"d:\temp\question28328432.json";
            string url = @"http://steamcommunity.com/id/Mambocsgoshack/inventory/json/730/2/";
            var inventory = CSGOInventory.FetchInventoryFromUrl(new Uri(url));
            foreach (var market in inventory.MarketNames)
            {
                Console.WriteLine(string.Format("    Market {0,-50}: id {1}", market, inventory.getInstanceIdFromMarketName(market)));
            }
        }
    }
    
    Market SG 553 | Army Sheen (Factory New)                 : id 1482735510
    Market Offer | Music Kit | Noisia, Sharpened             : id 1468698711
    Market Offer | Sticker | Bomb Squad (Foil)               : id 1468698710
    Market Offer | Sticker | Dinked                          : id 1468698709
    Market Offer | Sticker | Kawaii Killer CT                : id 1468698708
    Market Operation Breakout Weapon Case                    : id 1462270322
    Market Operation Vanguard Weapon Case                    : id 1459818809
    Market M4A4 | Howl (Minimal Wear)                        : id 1450750270
    Market Operation Phoenix Weapon Case                     : id 1391297747
    Market Negev | Army Sheen (Minimal Wear)                 : id 1370560151
    Market Huntsman Weapon Case                              : id 1305163655
    Market Tec-9 | Army Mesh (Minimal Wear)                  : id 1304896559
    Market Galil AR | Cerberus (Well-Worn)                   : id 1214784536
    Market StatTrakT Tec-9 | Sandstorm (Field-Tested)        : id 1201208194
    Market G3SG1 | Contractor (Field-Tested)                 : id 1189828757
    Market Campaign Vanguard                                 : id 1103736871
    Market Campaign Weapons Specialist                       : id 1103736870
    Market Operation Vanguard Challenge Coin                 : id 1103736869
    Market StatTrakT XM1014 | Red Python (Field-Tested)      : id 957595359
    Market StatTrakT CZ75-Auto | Hexane (Field-Tested)       : id 814442137
    Market Negev | Army Sheen (Factory New)                  : id 623936007
    Market SSG 08 | Sand Dune (Well-Worn)                    : id 616381102
    Market Silver Operation Breakout Coin                    : id 612997861
    Market UMP-45 | Scorched (Field-Tested)                  : id 603041123