如何使用Nethereum正确反序列化智能合约返回的自定义结构体数组?
解决Nethereum反序列化Solidity结构体数组的动态类型错误
你遇到的这个错误是因为Nethereum默认的CallAsync<T>方法在处理包含动态类型(比如Solidity中的string)的结构体数组时会受限。下面是具体的解决方法和代码调整:
错误原因分析
你的Solidity结构体DrugBox包含了string这种动态长度类型,而之前的C# DTO定义既没有正确标记每个字段的Solidity类型与顺序,又使用了不支持动态类型数组的CallAsync<DrugBoxesDTO>调用方式,最终触发了NotSupportedException。
正确的解决方案
我们需要调整DTO的定义,让它和Solidity结构体完全映射,同时使用Nethereum专门处理结构体数组的反序列化方法:
1. 修正DrugBoxDTO的字段映射
确保每个字段都用Parameter属性标记,顺序必须和Solidity结构体的定义顺序完全一致,并且使用正确的C#类型对应Solidity类型:
- Solidity的
uint256对应C#的BigInteger(避免int溢出) address可以用string或Nethereum的Address类型(后者更类型安全)string直接对应C#的string
using Nethereum.Contracts.Attributes; using Nethereum.Hex.HexTypes; using Nethereum.Model; public class DrugBoxDTO { // 对应Solidity DrugBox的第一个字段:uint256 weight [Parameter("uint256", "weight", 1)] public BigInteger Weight { get; set; } // 对应第二个字段:uint256 creationDate [Parameter("uint256", "creationDate", 2)] public BigInteger CreationDate { get; set; } // 对应第三个字段:address producer [Parameter("address", "producer", 3)] public Address Producer { get; set; } // 用Address类型更类型安全 // 对应第四个字段:string drugName [Parameter("string", "drugName", 4)] public string DrugName { get; set; } // 对应第五个字段:uint256 id [Parameter("uint256", "id", 5)] public BigInteger Id { get; set; } }
2. 使用正确的调用方法
替换原来的CallAsync<DrugBoxesDTO>,改用CallDeserializableArrayAsync<T>方法直接反序列化结构体数组:
// 获取合约函数 var getAllBoxesFunc = drugStoreContract.GetFunction("getAllBoxes"); // 直接反序列化为DrugBoxDTO的列表 List<DrugBoxDTO> drugBoxes = await getAllBoxesFunc.CallDeserializableArrayAsync<DrugBoxDTO>();
额外注意事项
- 字段顺序是关键:Solidity结构体是按定义顺序存储字节数据的,Nethereum反序列化时完全依赖这个顺序,不能搞混。
- 数值类型匹配:不要用
int接收Solidity的uint256,因为uint256的取值范围远大于C#的int,会导致溢出错误,必须用BigInteger。 - 动态类型处理:如果结构体包含
bytes、string这类动态长度类型,必须确保DTO字段的Parameter类型标记正确,否则反序列化会失败。
内容的提问来源于stack exchange,提问作者Karyna Dorosh
相关产品推荐
相关产品推荐

