概述:
我正在尝试制作一个应用程序,将本地 JSON 反序列化为列表,然后将其转换为 DataTable,然后将其显示到 DataGridView 中。
我正在使用的数据是用于交易卡牌游戏 JSON 包含卡牌列表,每个卡牌对象都有一堆属性、语言、名称等……
下面将详细介绍数据源。
问题:
我有一个半工作项目,但我无法弄清楚为什么一些属性和数据值在反序列化时没有传递到我的列表中,因为对象没有 RootObjectLevel
。
每次使用比根级别更深的 { } 封装 abject 时,例如 legalities
在下面的代码中,我的 DataGridView 只显示一列带有 (Collection) 或namespace.classname
而不是所有属性列。
用于描述上述内容的示例压缩 JSON 代码(之后提供完整的 JSON)
{
"lang": "en",
"set": "lea",
"set_name": "Limited Edition Alpha",
"collector_number": "142",
"name": "Dwarven Demolition Team",
"legalities": {
"standard": "not_legal",
"future": "not_legal",
"historic": "not_legal",
"gladiator": "not_legal",
"pioneer": "not_legal",
"modern": "legal",
"legacy": "legal",
"pauper": "not_legal",
"vintage": "legal",
"penny": "not_legal",
"commander": "legal",
"brawl": "not_legal",
"duel": "legal",
"oldschool": "legal",
"premodern": "not_legal"
},
}
为卡片返回的完整 JSON 示例,因此您可以查看整个内容:
https ://api.scryfall.com/cards/03482c9c-1f25-4d73-9243-17462ea37ac4
您可以选择查看原始数据,甚至可以对其进行格式化,使其像上面那样易于阅读。
JSON 数据源 – https://scryfall.com/docs/api/bulk-data
我正在使用 « Default Cards » 和 « All Cards » 文件,第二个是 1,2Go
目标:
我想要实现的正常行为或结果是将“合法性”中的所有 15 个不同对象显示为标题:{}
| 标准 | 未来 | 历史 | ETC...
以及每行每张卡片的legal
or值。not legal
我的猜测:
我没有任何错误,它适用于所有数据,RootObject
但数据比RootObjectLevel
仅仅返回 null 或没有以某种方式正确填充列表。
我怀疑我需要一个自定义转换器,一个令牌阅读器,也许使用字典或类似的东西,但在寻找一周后我只是一无所知,我对 C# 太陌生了,我猜,它已经像 2 周以来我开始编码。
我什至不确定我是否能够记住到目前为止我感到疲倦的所有事情,并在此处列出它们,但是当我尝试再次进行新搜索时,并没有那么多链接显示为“未读”解决我的问题。
到目前为止,我已经能够在 Google 上找到我需要的东西,但这次我需要一些帮助。
现在代码:
pictureBox_Click
打开我的本地 JSON 并将其路径写入Label.Text
private void pictureBoxScryfallOpenFile_Click(object sender, EventArgs e)
{
using (var openFileDialog = new OpenFileDialog())
{
openFileDialog.Title = "Please select a JSON file";
openFileDialog.Filter = "JSON files (*.json) | *.json";
openFileDialog.RestoreDirectory = true;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string fileName = openFileDialog.FileName;
labelScryfallOpenedFile.Visible = true;
labelScryfallOpenedFile.Text = fileName;
}
}
}
然后我从新的路径中获取路径以Label.Text
开始反序列化。label.Text.ToString()
buttom_Click
除此之外,我还有一个带有 4 个选项的 ComboBox,每个选项都在If
调用触发具有我想从文件中读取的 JSONProperty 的好类
然后我将我的对象列表反序列化为一个列表,该列表被转换为一个设置为 DataGridView 的数据源的 DataTable。
我正在缩小没有 ComboBox 和重现问题的最少代码的代码。
using Newtonsoft.Json;
public void buttonReadScryfall_Click(object sender, EventArgs e)
{
if (labelScryfallOpenedFile.Visible == true)
{
string jsonFilePath = labelScryfallOpenedFile.Text.ToString();
using (var jsonFile = new StreamReader(jsonFilePath))
{
var jsonTextReader = new JsonTextReader(jsonFile);
var serializer = new JsonSerializer();
var cardLegalities = serializer.Deserialize<List<CardLegalities>>(jsonTextReader);
DataTable dtLegalities = ConvertToDataTable(cardLegalities);
dataGridView.DataSource = null;
dataGridView.DataSource = dtLegalities;
dataGridView.Refresh();
}
}
else
{
MessageBox.Show("!!! No File Selected !!!"
+ Environment.NewLine +
"Open a Local File Using the Appropriate Folder Icon"
+ Environment.NewLine +
"Before Attempting to Deserialize a JSON");
}
}
注意:
我需要 StreamReader,在这种情况下它甚至是强制性的,如果我使用标准reader.ReadAllText()
,它最终会出现内存不足异常,因为我正在使用的最大文件是 1.2Go,我们正在谈论超过 300k 行如果我决定使用可用于每张卡的整个 JSON 属性,则有一百列。
我还需要转换为 DataTable,否则我无法使用DefaultView.RowFilter
.
转换为数据表
public static DataTable ConvertToDataTable<T>(IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
最后是随之而来的类:
using Newtonsoft.Json;
public class CardLegalities
{
[JsonProperty("lang")]
public string Lang { get; set; }
[JsonProperty("set")]
public string Set { get; set; }
[JsonProperty("set_name")]
public string SetName { get; set; }
[JsonProperty("collector_number")]
public string CollectorNumber { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// An object describing the legality of this card in different formats
/// </summary>
[JsonProperty("legalities")]
public Legalities Legalities { get; set; }
}
public class Legalities
{
[JsonProperty("standard")]
public string Standard { get; set; }
[JsonProperty("future")]
public string Future { get; set; }
[JsonProperty("historic")]
public string Historic { get; set; }
[JsonProperty("gladiator")]
public string Gladiator { get; set; }
[JsonProperty("pioneer")]
public string Pioneer { get; set; }
[JsonProperty("modern")]
public string Modern { get; set; }
[JsonProperty("legacy")]
public string Legacy { get; set; }
[JsonProperty("pauper")]
public string Pauper { get; set; }
[JsonProperty("vintage")]
public string Vintage { get; set; }
[JsonProperty("penny")]
public string Penny { get; set; }
[JsonProperty("commander")]
public string Commander { get; set; }
[JsonProperty("brawl")]
public string Brawl { get; set; }
[JsonProperty("duel")]
public string Duel { get; set; }
[JsonProperty("oldschool")]
public string Oldschool { get; set; }
[JsonProperty("premodern")]
public string Premodern { get; set; }
}
我真的很想知道如何解决这个问题,我很确定我会看到一些我在 Google 搜索中看到但无法适应我的需求的东西,因为我对 C# 编码太陌生了。
如果这样更方便的话,我最终可以将应用程序推送到 GitHub 以便您克隆存储库。