/// <summary> /// 按照数据规范输出数据 /// </summary> /// <param name="context">当前字节序列上下文</param> /// <param name="writer">二进制写入器</param> /// <param name="respDict">输出数据词典</param> /// <param name="contracts">当前协议规范</param> public static void WriteByContract(StreamContext context, BinaryWriter writer, Dictionary <string, object> respDict, DataContract contracts) { context.ContextObjectDictionary = respDict; foreach (DataItem item in contracts.TransItems) { #region 判断是否写入当前项 if (!string.IsNullOrEmpty(item.ConditionalExpression)) { if (!new SpecExpression(item.ConditionalExpression).IsPass(context)) { continue; } } #endregion SpecDataType dType = SpecDataType.Parse(context, item.DataType); Type clrType = dType.GetRuntimeType(); if (clrType == null) { throw new SpecDataDefineException(string.Format("数据类型{0}不能识别!", item.DataType)); } else { WriteKnownTypeObject(context, writer, dType, respDict[item.DataName], item.NetworkBytes); } //设置最近一个解析项 context._lastDataItem = item; } }
/// <summary> /// 按照数据规范读取数据为数据词典 /// </summary> /// <param name="context">当前字节序列上下文</param> /// <param name="reader">二进制读取器</param> /// <param name="contracts">协议规范</param> /// <returns></returns> public static Dictionary <string, object> ReadByContract(StreamContext context, BinaryReader reader, DataContract contracts) { Dictionary <string, object> reqDict = new Dictionary <string, object>(StringComparer.InvariantCultureIgnoreCase); context.ContextObjectDictionary = reqDict; foreach (DataItem item in contracts.TransItems) { #region 判断是否读取当前项 if (!string.IsNullOrEmpty(item.ConditionalExpression)) { if (!new SpecExpression(item.ConditionalExpression).IsPass(context)) { continue; } } #endregion SpecDataType dType = SpecDataType.Parse(context, item.DataType); Type clrType = dType.GetRuntimeType(); if (clrType == null) { throw new SpecDataDefineException(string.Format("数据类型{0}不能识别!", item.DataType)); } else { reqDict[item.DataName] = ReadKnownTypeObject(context, reader, dType); } //设置最近一个解析项 context._lastDataItem = item; } return(reqDict); }
/// <summary> /// 在当前上下文中写入已知类型数据,并移动上下文写入游标索引。 /// </summary> /// <param name="context">当前字节序列上下文</param> /// <param name="writer">二进制写入器</param> /// <param name="dType">规范数据定义</param> /// <param name="objData">写入对象实例</param> /// <param name="isNetworkBytes">是否写入网络序</param> public static void WriteKnownTypeObject(StreamContext context, BinaryWriter writer, SpecDataType dType, object objData, bool isNetworkBytes) { Type clrType = dType.GetRuntimeType(); if (dType.Prototype == SpecDataPrototype.Native) { context.IncreasePosition(SpecData.CLRObjectWrite(clrType, writer, objData, isNetworkBytes)); } else { if (dType.Prototype == SpecDataPrototype.Array) { Type elementType = dType.GetElementType(); Array arrObj = (Array)objData; if (SpecDataType.IsNativeType(TypeCache.ToSimpleType(elementType))) { #region 写入基础数据类型数组 for (int i = 0, j = dType.ElementLength; i < j; i++) { context.IncreasePosition(SpecData.CLRObjectWrite(elementType, writer, arrObj.GetValue(i), isNetworkBytes)); } #endregion } else { for (int m = 0, n = dType.ElementLength; m < n; m++) { WriteKnownTypeObject(context, writer, dType.GetElementDataType(), arrObj.GetValue(m), isNetworkBytes); } } } else { #region 扩展写入 if (clrType.Equals(typeof(EnumContract))) { EnumContract enc = (EnumContract)dType.GetDefineInstance(); clrType = enc.GetBaseRuntimeType(); if (!objData.GetType().Equals(clrType)) { objData = enc.GetEnumUnderlyingValue(objData.ToString()); } context.IncreasePosition(SpecData.CLRObjectWrite(clrType, writer, objData, isNetworkBytes)); } else if (clrType.Equals(typeof(DataContract))) { DataContract dac = (DataContract)dType.GetDefineInstance(); WriteByContract(context, writer, (Dictionary <string, object>)objData, dac); } else { throw new SpecDataDefineException(string.Format("不能读取数据类型{0}!", clrType.FullName)); } #endregion } } }
/// <summary> /// 解析数据类型 /// </summary> /// <param name="context">当前解析上下文</param> /// <param name="rawTypeDefine">原始定义字符串</param> /// <returns></returns> public static SpecDataType Parse(StreamContext context, string rawTypeDefine) { SpecDataType sType = new SpecDataType(); sType.TypeName = rawTypeDefine; int idx = -1, idx2 = -1; idx = rawTypeDefine.IndexOf('['); idx2 = rawTypeDefine.IndexOf(']'); if (idx != -1 && idx2 != -1) { if (idx2 - idx == 1) { throw new SpecDataDefineException("数组类型定义[" + rawTypeDefine + "]错误,[]必须包含数据项长度或使用上下文计算的-1!"); } sType.Prototype = SpecDataPrototype.Array; string strTemp = rawTypeDefine.Substring(0, idx); SpecDataType esType = Parse(context, strTemp); sType._elementType = esType.GetRuntimeType(); sType.eleSpecDataType = esType; strTemp = rawTypeDefine.Substring(idx + 1, idx2 - idx - 1).Trim(); if (strTemp == "-1") { DataItem?item = context.GetLastDataItem(); if (!item.HasValue) { throw new SpecDataDefineException("数组类型定义[-1]在上下文中没有前置传输定义项!"); } else { sType.ElementLength = Convert.ToInt32(context.ContextObjectDictionary[item.Value.DataName]); } } else { if (!context.ContextObjectDictionary.ContainsKey(strTemp)) { throw new SpecDataDefineException("数组长度定义[" + strTemp + "]在上下文的没有找到长度定义!"); } else { sType.ElementLength = Convert.ToInt32(context.ContextObjectDictionary[strTemp]); } } sType.SetRuntimeType(sType._elementType.MakeArrayType()); } else { #region 非数组定义 if (IsNativeType(rawTypeDefine)) { sType.Prototype = SpecDataPrototype.Native; sType.SetRuntimeType(TypeCache.GetRuntimeType(rawTypeDefine)); } else { SpecFile specDef = context.ContractSpec; EnumContract enc = TypeCache.FirstOrDefault <EnumContract>(specDef.AllDefinition, d => d.TypeName.Equals(rawTypeDefine)); if (enc != null) { sType.Prototype = SpecDataPrototype.Enum; sType.SetRuntimeType(typeof(EnumContract)); sType.typeDefineInstance = enc; } else { DataContract dac = TypeCache.FirstOrDefault <DataContract>(specDef.AllImportContracts, c => c.ContractName.Equals(rawTypeDefine)); if (dac == null) { throw new SpecDataDefineException("类型定义" + rawTypeDefine + "不能识别!"); } sType.Prototype = SpecDataPrototype.Composite; sType.SetRuntimeType(typeof(DataContract)); sType.typeDefineInstance = dac; } } #endregion } return(sType); }
/// <summary> /// 在当前上下文中读取已知类型读取数据,并移动上下文读取游标索引。 /// </summary> /// <param name="context">当前字节序列上下文</param> /// <param name="reader">二进制读取器</param> /// <param name="dType">规范数据定义</param> /// <returns></returns> public static object ReadKnownTypeObject(StreamContext context, BinaryReader reader, SpecDataType dType) { object itemObj = null; Type clrType = dType.GetRuntimeType(); if (dType.Prototype == SpecDataPrototype.Native) { itemObj = SpecData.CLRObjectFromReader(clrType, reader); context.IncreasePosition(SpecData.GetCLRTypeByteLength(clrType)); } else { if (dType.Prototype == SpecDataPrototype.Array) { Type elementType = dType.GetElementType(); Array arrObj = Array.CreateInstance(elementType, dType.ElementLength); if (SpecDataType.IsNativeType(TypeCache.ToSimpleType(elementType))) { #region 读取基础数据类型数组 long unitLen = SpecData.GetCLRTypeByteLength(elementType); for (int i = 0, j = dType.ElementLength; i < j; i++) { arrObj.SetValue(SpecData.CLRObjectFromReader(elementType, reader), i); context.IncreasePosition(unitLen); } #endregion } else { for (int m = 0, n = dType.ElementLength; m < n; m++) { arrObj.SetValue(ReadKnownTypeObject(context, reader, dType.GetElementDataType()), m); } } itemObj = arrObj; } else { #region 扩展读取 if (clrType.Equals(typeof(EnumContract))) { EnumContract enc = (EnumContract)dType.GetDefineInstance(); clrType = enc.GetBaseRuntimeType(); itemObj = SpecData.CLRObjectFromReader(clrType, reader); context.IncreasePosition(SpecData.GetCLRTypeByteLength(clrType)); } else if (clrType.Equals(typeof(DataContract))) { DataContract dac = (DataContract)dType.GetDefineInstance(); itemObj = ReadByContract(context, reader, dac); } else { throw new SpecDataDefineException(string.Format("不能读取数据类型{0}!", clrType.FullName)); } #endregion } } return(itemObj); }