C#实现Crestron JSON反序列化并传递数组到Simpl+问题咨询
Crestron Simpl# JSON反序列化列表字段回传Simpl+失败解决方案
问题根因
能正常读取total这类简单值/字符串字段,但无法读取clients这类列表成员,核心是Crestron Simpl+互操作层的三个特有约束,和通用.NET JSON反序列化逻辑无关:
- Simpl+ 不支持泛型
List<T>类型的跨程序集封送,Simpl+可识别的集合类型仅为定长数组、Simpl+原生声明的数组结构,泛型集合会被封送层识别为未知类型,无法返回正确数据 - 所有需要暴露给Simpl+的类、嵌套类如果未添加可见性标记,即使内存中反序列化出了正确值,封送层也无法读取嵌套属性(比如
Hardware、Network这类Client下的嵌套对象) - Simpl+ 不支持
object类型的封送,类定义中如果存在object类型字段,会导致整个对象的封送流程异常
修复步骤
- 第一步:调整类结构适配Simpl+互操作规则
把所有泛型列表替换为定长数组,将所有object类型字段替换为string类型,给所有需要暴露给Simpl+的类添加[SimplVisible]特性(需要引用Crestron.SimplSharp、Crestron.SimplSharp.Reflection命名空间),调整后的类代码如下:
using Crestron.SimplSharp; using Crestron.SimplSharp.Reflection; [SimplVisible] public class Client { public string clientId { get; set; } public string locale { get; set; } public string location { get; set; } public string auxiliaryId { get; set; } public string description { get; set; } public string type { get; set; } public string typeDescription { get; set; } public Hardware hardware { get; set; } public Network network { get; set; } } [SimplVisible] public class Hardware { public string type { get; set; } public string softwareVersion { get; set; } public string serialNumber { get; set; } public string hardwareVersion { get; set; } public string model { get; set; } } [SimplVisible] public class Network { public string ip { get; set; } public string mac { get; set; } public string homepage { get; set; } public string dhcpSubnet { get; set; } } [SimplVisible] public class Result { // 替换原List<Client>为定长Client数组 public Client[] clients { get; set; } public string total { get; set; } public int limit { get; set; } public int page { get; set; } } [SimplVisible] public class Root { public string jsonrpc { get; set; } // 替换原object类型为string public string id { get; set; } public Result result { get; set; } }
- 第二步:反序列化与数据预处理
优先使用Crestron固件预置的Newtonsoft.Json做反序列化,不要使用高版本System.Text.Json避免兼容性问题;反序列化完成后必须对数组做定长补全,避免Simpl+读取时出现空引用、越界问题,示例代码如下:
// 执行反序列化 Root root = JsonConvert.DeserializeObject<Root>(rawJsonText); // Simpl+侧约定的数组最大长度,两边必须完全一致 const int SimplMaxClientCount = 100; Client[] sPlusClientArray = new Client[SimplMaxClientCount]; if (root?.result != null) { // 赋值已读取到的简单字段 exposedToSimplPlus.Total = root.result.total; exposedToSimplPlus.Limit = root.result.limit; exposedToSimplPlus.Page = root.result.page; // 处理客户端列表 int actualClientCount = root.result.clients?.Length ?? 0; int copyLength = actualClientCount > SimplMaxClientCount ? SimplMaxClientCount : actualClientCount; for (int i = 0; i < SimplMaxClientCount; i++) { if (i < copyLength) { sPlusClientArray[i] = root.result.clients[i]; } else { // 空位补全空实例,避免Simpl+读取null触发异常 sPlusClientArray[i] = new Client { hardware = new Hardware(), network = new Network() }; } } exposedToSimplPlus.Clients = sPlusClientArray; }
- 第三步:Simpl+侧对应声明
Simpl+侧必须声明和C#侧结构完全匹配的结构体、定长数组,数组长度、字符串预留长度必须对齐,示例声明如下:
STRUCT Hardware { STRING type[200]; STRING softwareVersion[100]; STRING serialNumber[100]; STRING hardwareVersion[100]; STRING model[100]; }; STRUCT Network { STRING ip[50]; STRING mac[50]; STRING homepage[200]; STRING dhcpSubnet[50]; }; STRUCT Client { STRING clientId[100]; STRING locale[20]; STRING location[200]; STRING auxiliaryId[100]; STRING description[500]; STRING type[50]; STRING typeDescription[200]; Hardware hardware; Network network; }; // 输出声明,数组长度和C#侧完全一致 Client clients[100]; STRING total[10]; INTEGER limit; INTEGER page;
注意:Simpl+侧字符串预留长度必须大于实际可能返回的字符串长度,长度不足会导致字符串截断,甚至触发Simpl程序运行时崩溃;如果仍读取不到列表数据,先检查JSON字段名大小写是否和类属性名匹配,Newtonsoft.Json默认大小写不敏感,第三方简易JSON解析器通常要求大小写完全一致。
内容的提问来源于stack exchange,提问作者brad wykoff
相关产品推荐
相关产品推荐

