C#中如何从动态增长的长JSON文件获取最新交易的DestinationTag
问题描述
我现在在C#里用dynamic变量读取长JSON文件,但新交易生成导致交易条目增加时,这种方式没法获取最新交易的DestinationTag——因为dynamic绑定的是特定位置的数值。请问该怎么解决?
相关JSON示例片段:
{ "result":"success", "count":5, "transactions":[ { "hash":"866B841C8C3B2D840497679FAC45A7D4341E12056AAA53F67471CA1B955FB58E", "ledger_index":37860930, "date":"2018-04-10T12:35:32+00:00", "tx":{ "TransactionType":"Payment", "Flags":2147483648, "SourceTag":0, "Sequence":20, "DestinationTag":0, "LastLedgerSequence":37860958, "Amount":"25000000", "Fee":"12", "SigningPubKey":"02917EB4353C539A2B0766EFAB1723E5BB744516C673FFCF21457DAD44BCECFE25", "TxnSignature":"304402202FA9FF18A572ACA1735B54CF5A69E10398EAF7003F3573E402ABA09B404F765C0220773481B494A941CC0F5338836A6B71F5FA2499943C41D50205C8EF158651BD86", "Account":"rLcqTPYFSJBWGmu2ZXh8JTYGgdXRPjWTrx", "Destination":"rfginNsDts73fZtzp858dT6Y6U67Y1QB7GV" }, "meta":{ "TransactionIndex":1, "AffectedNodes":[ { "CreatedNode":{ "LedgerEntryType":"AccountRoot", "LedgerIndex":"1C75CD43D75614E00025102355ADCCCF6302FAD5B82DC85F5AAF5696E4E39EC4", "NewFields":{ "Sequence":1, "Balance":"25000000", "Account":"rfginNsDt73fZtzp858dT6Y6U6s7Y1QB7GV" } } }, { "ModifiedNode":{ "LedgerEntryType":"AccountRoot", "PreviousTxnLgrSeq":37757840, "PreviousTxnID":"C794D81D17DF1EA735200E50B9CEADDF19160841E1321F08FDB7C7C4D6BC41AF", "LedgerIndex":"BE486CB1FED1B1805E4C42E8E96C73CFDA4E520C66BACEBBE441C1F8212D980E", "PreviousFields":{ "Sequence":20, "Balance":"537421240" }, "FinalFields":{ "Flags":0, "Sequence":21, "OwnerCount":0, "Balance":"512421228", "Account":"rLcqTPYFSJBWGmu2ZXh8JTYGgdXRPjWTrx" } } } ], "TransactionResult":"tesSUCCESS", "delivered_amount":"25000000" } }, { "hash":"86E5D976DDCBF97047C86996286751B23C4384A8B4F6A04E38A57F30F54749CC", "ledger_index":38906860, "date":"2018-05-25T10:04:22+00:00", "tx":{ "TransactionType":"Payment", "Flags":2147483648, "Sequence":28534, "DestinationTag":2150, "Amount":"25000000", "Fee":"45", "SigningPubKey":"", "Account":"rG2uw1W9FXoiY4QiNqej5WeRxnoBEw4JbL", "Destination":"rfginNsDt73fZtzp858dT6Y6U67Y1QB7GV", "Signers":[ { "Signer":{ "SigningPubKey":"032DCABB7A17A96E826435B461E474CB33C86C98B2281D304367FCFC6DE463A215", "TxnSignature":"3045022100F9802AE2F7800D42233A5B63999C0BD7AE5B7D60D8244C949FF81EA39959B4BC02205E37DD331ACE2637F2BEE758B5AD642D259F4140E8DE53EF610B6F58745BCC05", "Account":"rDc4zYyxMbXfUXNKw6zfM88RBUd9y8uPYX" } }, { "Signer":{ "SigningPubKey":"03019752C3ABCB2BC89EC5FAEF55D72AE940820A30FBA079D2BB8CE8841174EF21", "TxnSignature":"30450221009C7F9519912D494C9F009130927E1248BE6C2F877B1A913B49B8BFD926442F6802205377D1D242D07033DC6FDA8C93BC65638D636A87539F32A0D269AA9B537FCB0D", "Account":"rKB5N7FxvcwHSYq4NCKjyMpjML1MznMrFc" } } ] }, "meta":{ "TransactionIndex":17, "AffectedNodes":[ { "ModifiedNode": {} } ] } } ] }
解决方案
用dynamic确实容易遇到这种绑定固定位置的问题,毕竟它是编译时不检查类型、运行时才解析的,没法自动适应数组长度变化。这里给你几个实用的解决思路:
1. 使用强类型模型(推荐)
最稳妥的方式是把JSON结构映射成C#类,这样不管交易条目怎么增加,都能通过遍历集合拿到所有交易的DestinationTag,包括最新的。
首先根据你的JSON结构生成对应的类(可以用Visual Studio的「编辑 > 选择性粘贴 > 将JSON粘贴为类」功能快速生成):
public class TransactionResponse { public string result { get; set; } public int count { get; set; } public List<Transaction> transactions { get; set; } } public class Transaction { public string hash { get; set; } public int ledger_index { get; set; } public string date { get; set; } public Tx tx { get; set; } public Meta meta { get; set; } } public class Tx { public string TransactionType { get; set; } public long Flags { get; set; } public int? SourceTag { get; set; } // 用可空类型处理可能缺失的字段 public int Sequence { get; set; } public int? DestinationTag { get; set; } public int? LastLedgerSequence { get; set; } public string Amount { get; set; } public string Fee { get; set; } public string SigningPubKey { get; set; } public string TxnSignature { get; set; } public string Account { get; set; } public string Destination { get; set; } public List<SignerWrapper> Signers { get; set; } } public class SignerWrapper { public Signer Signer { get; set; } } public class Signer { public string SigningPubKey { get; set; } public string TxnSignature { get; set; } public string Account { get; set; } } public class Meta { public int TransactionIndex { get; set; } public List<AffectedNode> AffectedNodes { get; set; } public string TransactionResult { get; set; } public string delivered_amount { get; set; } } public class AffectedNode { public CreatedNode CreatedNode { get; set; } public ModifiedNode ModifiedNode { get; set; } } public class CreatedNode { public string LedgerEntryType { get; set; } public string LedgerIndex { get; set; } public NewFields NewFields { get; set; } } public class NewFields { public int Sequence { get; set; } public string Balance { get; set; } public string Account { get; set; } } public class ModifiedNode { public string LedgerEntryType { get; set; } public int? PreviousTxnLgrSeq { get; set; } public string PreviousTxnID { get; set; } public string LedgerIndex { get; set; } public PreviousFields PreviousFields { get; set; } public FinalFields FinalFields { get; set; } } public class PreviousFields { public int Sequence { get; set; } public string Balance { get; set; } } public class FinalFields { public int Flags { get; set; } public int Sequence { get; set; } public int OwnerCount { get; set; } public string Balance { get; set; } public string Account { get; set; } }
然后用Newtonsoft.Json(或者System.Text.Json)反序列化,之后就能轻松遍历所有交易,拿到最新的DestinationTag:
// 假设jsonString是你的JSON内容 var response = JsonConvert.DeserializeObject<TransactionResponse>(jsonString); // 获取所有交易的DestinationTag,包括最新的 var allDestinationTags = response.transactions .Where(t => t.tx.DestinationTag.HasValue) .Select(t => t.tx.DestinationTag.Value) .ToList(); // 如果要拿最新的那笔交易的DestinationTag(假设transactions数组最后一个是最新的) var latestDestinationTag = response.transactions.LastOrDefault()?.tx.DestinationTag;
2. 使用JObject遍历(无需强类型)
如果不想定义一堆类,可以用Newtonsoft.Json的JObject来动态解析,直接遍历transactions数组:
var jObject = JObject.Parse(jsonString); var transactions = jObject["transactions"] as JArray; // 遍历所有交易,提取DestinationTag foreach (var txObj in transactions) { var destinationTag = txObj["tx"]["DestinationTag"]?.Value<int>(); if (destinationTag.HasValue) { // 处理这个值 Console.WriteLine(destinationTag.Value); } } // 获取最新的交易的DestinationTag var latestTx = transactions.LastOrDefault(); var latestTag = latestTx?["tx"]["DestinationTag"]?.Value<int>();
3. 避免直接绑定dynamic的索引
如果你一定要用dynamic,那不要直接写dynamic.transactions[0].tx.DestinationTag这种固定索引的代码,而是把它当成集合遍历:
dynamic response = JsonConvert.DeserializeObject(jsonString); foreach (var tx in response.transactions) { var tag = tx.tx.DestinationTag; if (tag != null) { // 处理tag } } // 拿最新的 var latestTx = response.transactions.LastOrDefault(); var latestTag = latestTx?.tx.DestinationTag;
这样不管transactions数组新增多少条目,都能遍历到所有元素,不会错过最新的交易。
内容的提问来源于stack exchange,提问作者Jitender
相关产品推荐
相关产品推荐

