using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Reflection; using System.Xml; using CommonLang.Xml; using System.IO.Compression; namespace CommonLang.IO { public static class IOUtil { public static byte TryReadByte(Stream data) { int b = data.ReadByte(); if (b < 0) { throw new IOException("EOF of stream"); } return (byte)b; } /// /// 从输入流复制到输出流 /// /// 输入流 /// 输出流 /// 总共复制多少字节 /// 进度回调,返回False表示终止进程 /// 缓冲区大小 /// public static bool ReadTo(Stream input, Stream output, long total_bytes, Predicate progress, int buffer_size = 16384) { byte[] io_buffer = new byte[buffer_size]; long total_readed = 0; while (total_readed < total_bytes) { if (!progress(0)) return false; int expect = (int)Math.Min(io_buffer.Length, total_bytes - total_readed); int readed = input.Read(io_buffer, 0, expect); total_readed += readed; if (!progress(readed)) return false; output.Write(io_buffer, 0, readed); } output.Flush(); return true; } public static byte[] ReadExpect(Stream input, int count) { if (count == 0) return new byte[0]; byte[] data = new byte[count]; ReadToEnd(input, data, 0, count); return data; } public static void ReadToEnd(Stream input, byte[] data, int offset, int count) { if (count == 0) return; int readed = input.Read(data, offset, count); if (readed <= 0) throw new IOException("EOF of stream"); while (readed < count) { int bytes = input.Read(data, offset + readed, count - readed); if (bytes <= 0) { throw new IOException("EOF of stream"); } readed += bytes; } } public static void ReadToEnd(Stream src, Stream dst) { byte[] buffer = new byte[1024]; while (true) { int readed = src.Read(buffer, 0, buffer.Length); if (readed > 0) { dst.Write(buffer, 0, readed); } else { break; } } } public static byte[] ReadToEnd(Stream src) { using (MemoryStream dst = new MemoryStream()) { ReadToEnd(src, dst); return dst.ToArray(); } } public static void WriteToEnd(Stream output, byte[] data, int offset, int count) { output.Write(data, offset, count); } public static T CloneIExternalizable(IExternalizableFactory decode, T src) where T : IExternalizable, new() { if (src != null) { T ret = new T(); { using (MemoryStream ms = new MemoryStream()) { src.WriteExternal(new OutputStream(ms, decode)); ms.Position = 0; ret.ReadExternal(new InputStream(ms, decode)); } } return ret; } return default(T); } public static IExternalizable Clone(IExternalizableFactory decode, IExternalizable src) { IExternalizable ret = null; if (src != null) { using (MemoryStream ms = new MemoryStream()) { new OutputStream(ms, decode).PutExt(src); ms.Position = 0; ret = new InputStream(ms, decode).GetExtAny(); } } return ret; } public static byte[] LoadFromAssembly(Assembly assembly, string resource) { Stream stream = assembly.GetManifestResourceStream(resource); byte[] ret = new byte[stream.Length]; /*stream.Read(ret, 0, ret.Length);*/ IOUtil.ReadToEnd(stream, ret, 0, ret.Length); return ret; } public static byte[] ObjectToBin(IExternalizableFactory decode, IExternalizable ext) { using (MemoryStream ms = new MemoryStream()) { OutputStream output = new OutputStream(ms, decode); output.PutExt(ext); int len = (int)ms.Position; byte[] buffer = ms.GetBuffer(); Array.Resize(ref buffer, len); return buffer; } } public static T BinToObject(IExternalizableFactory decode, byte[] data) where T : IExternalizable, new() { if (data == null || data.Length == 0) return default(T); using (MemoryStream ms = new MemoryStream(data)) { var input = new InputStream(ms, decode); return input.GetExt(); } } public static IExternalizable BinToObjectAny(IExternalizableFactory decode, byte[] data) { if (data == null || data.Length == 0) return null; using (MemoryStream ms = new MemoryStream(data)) { InputStream input = new InputStream(ms, decode); return input.GetExtAny(); } } public static void Zip(Stream src, Stream dst) { GZipStream zipStream = null; try { zipStream = new GZipStream(dst, CompressionMode.Compress, true); byte[] buffer = new byte[Math.Min(1024, src.Length)]; while (true) { int bytesRead = src.Read(buffer, 0, buffer.Length); if (bytesRead == 0) break; zipStream.Write(buffer, 0, bytesRead); } zipStream.Flush(); dst.Flush(); } finally { if (zipStream != null) zipStream.Close(); } } public static void Unzip(Stream src, Stream dst) { GZipStream zipStream = null; try { // Create a compression stream pointing to the destiantion stream zipStream = new GZipStream(src, CompressionMode.Decompress, true); // Read the footer to determine the length of the destiantion file byte[] buffer = new byte[1024]; // Read the compressed data into the buffer while (true) { int bytesRead = zipStream.Read(buffer, 0, buffer.Length); if (bytesRead == 0) break; dst.Write(buffer, 0, bytesRead); } dst.Flush(); } finally { if (zipStream != null) zipStream.Close(); } } public static byte[] Zip(byte[] data) { // Read in the compressed source stream MemoryStream src = new MemoryStream(data); MemoryStream dst = new MemoryStream(data.Length * 2); try { Zip(src, dst); byte[] ret = new byte[dst.Position]; Array.Copy(dst.GetBuffer(), 0, ret, 0, ret.Length); return ret; } catch (Exception err) { Console.WriteLine(err.Message + "\r" + err.StackTrace); return null; } finally { if (src != null) src.Close(); if (dst != null) dst.Close(); } } public static byte[] Unzip(byte[] data) { // Read in the compressed source stream MemoryStream src = new MemoryStream(data); MemoryStream dst = new MemoryStream(data.Length); try { Unzip(src, dst); byte[] ret = new byte[dst.Position]; Array.Copy(dst.GetBuffer(), 0, ret, 0, ret.Length); return ret; } catch (Exception err) { Console.WriteLine(err.Message + "\r" + err.StackTrace); return null; } finally { if (src != null) src.Close(); if (dst != null) dst.Close(); } } } public interface IExternalizable { void WriteExternal(IOutputStream output); void ReadExternal(IInputStream input); } public interface IExternalizableFactory { int GetTypeID(Type type); Type GetType(int id); } public enum DataType : byte { NA = 0, U8 = 1, S8 = 2, U16 = 3, S16 = 4, U32 = 5, S32 = 6, U64 = 7, S64 = 8, F32 = 9, F64 = 10, UTF = 11, EXT = 12, UC = 13, } public delegate T GetData(); public delegate void PutData(T v); public abstract class IOStream { public static int DEFAULT_ARRAY_LIMIT = UInt16.MaxValue; public static int DEFAULT_BYTES_LIMIT = 100 * 1024 * 1024; public int ARRAY_LIMIT = DEFAULT_ARRAY_LIMIT; public int BYTES_LIMIT = DEFAULT_BYTES_LIMIT; } public abstract class IOutputStream : IOStream { protected static System.Text.UTF8Encoding utfenc = new System.Text.UTF8Encoding(false); public IOutputStream(IExternalizableFactory factory) { this.Factory = factory; } public IExternalizableFactory Factory { get; private set; } #region _Abstract_ public abstract void PutBytes(byte[] bytes); public abstract void PutRawData(byte[] bytes, int offset, int count); public abstract void PutBool(bool value); public abstract void PutU8(byte value); public abstract void PutS8(sbyte value); public abstract void PutU16(ushort value); public abstract void PutS16(short value); public abstract void PutU32(uint value); public abstract void PutS32(int value); public abstract void PutU64(ulong value); public abstract void PutS64(long value); public abstract void PutF32(float value); public abstract void PutF64(double value); public abstract void PutUnicode(char value); public abstract void PutUTF(string str); public abstract long GetBuffPos(); #endregion #region _基础类型_ /// /// 写入可变长度32位 /// public void PutVU32(uint value) { PutVU64(value); } /// /// 写入可变长度32位 /// public void PutVS32(int value) { PutVS64(value); } /// /// 写入可变长度64位 /// public void PutVS64(long value) { ulong m; if (value < 0) { m = (ulong)(((-value) << 1) | 1); } else { m = (ulong)(((value) << 1)); } PutVU64(m); } /// /// 写入可变长度64位 /// public void PutVU64(ulong value) { do { byte b = (byte)(value & 0x7F); value = (value >> 7); if (value != 0) { b = (byte)(b | 0x80); } this.PutU8(b); } while (value != 0); } public void PutEnum8(ValueType enum8) { byte u8 = (byte)enum8; PutU8(u8); } public void PutEnum32(ValueType enum32) { int s32 = (int)enum32; PutS32(s32); } public void PutEnum8(T enum8) { byte u8 = Convert.ToByte(enum8); PutU8(u8); } public void PutEnum32(T enum32) { int s32 = Convert.ToInt32(enum32); PutS32(s32); } #endregion #region _对象类型_ public void PutExt(IExternalizable value) { if (value != null) { int typeID = Factory.GetTypeID(value.GetType()); if (typeID != 0) { PutS32(typeID); value.WriteExternal(this); //if(typeID != 0x8601 && typeID != 0x8006 && typeID != 0x8100 && typeID != 0x4003 && typeID != 0x4004 && typeID != 0x000B0010 & // typeID != 0x4009 && typeID != 0x4104 && typeID != 0x4109 && typeID != 0x8407 && typeID != 0x9001012 && typeID != 0xF000024 && // typeID != 0xF00001D && typeID != 0x400B && typeID != 0x4107 && typeID != 0x400C && typeID != 0xF000038 && typeID != 0x400C && // typeID != 0x000B0005 && typeID != 0x900100A && typeID != 0x9001004 && typeID != 0x9001005 && typeID != 0x9001002 && // typeID != 0x9001013 && typeID != 0x000B0001 && typeID != 0x8401 && typeID != 0x8116 && typeID != 0x9001010 && // typeID != 0x9001016 && typeID != 0xF000008 && typeID != 0x9001003 && typeID != 0x9001006 && typeID != 0x4016 && typeID != 0x9005 && // typeID != 0x9002 && typeID != 0xF00001E && typeID != 0xF000015 && typeID != 0x9006 && typeID != 0x9010) //{ // Console.WriteLine(" -- putExt -- {0:x}", typeID); //} } else { PutS32(0); //log.Error("Can Not Resolve IExternalizable Message : " + value.GetType()); throw new IOException("Can Not Resolve IExternalizable Message : " + value.GetType()); } } else { PutS32(0); } } public int GetTypeID(IExternalizable value) { return Factory.GetTypeID(value.GetType()); } public void PutObj2Xml(object obj) { if (obj != null) { XmlDocument x = XmlUtil.ObjectToXml(obj); string utf = XmlUtil.ToString(x); byte[] data = CUtils.UTF8.GetBytes(utf); PutBytes(data); } else { PutBytes(null); } } /// /// 自动检测类型 /// /// public void PutData(object value) { if (value is byte) { PutU8((byte)DataType.U8); PutU8((byte)value); } else if (value is sbyte) { PutU8((byte)DataType.S8); PutS8((sbyte)value); } else if (value is ushort) { PutU8((byte)DataType.U16); PutU16((ushort)value); } else if (value is short) { PutU8((byte)DataType.S16); PutS16((short)value); } else if (value is uint) { PutU8((byte)DataType.U32); PutU32((uint)value); } else if (value is int) { PutU8((byte)DataType.S32); PutS32((int)value); } else if (value is ulong) { PutU8((byte)DataType.U64); PutU64((ulong)value); } else if (value is long) { PutU8((byte)DataType.S64); PutS64((long)value); } else if (value is float) { PutU8((byte)DataType.F32); PutF32((float)value); } else if (value is double) { PutU8((byte)DataType.F64); PutF64((double)value); } else if (value is char) { PutU8((byte)DataType.UC); PutUnicode((char)value); } else if (value is string) { PutU8((byte)DataType.UTF); PutUTF((string)value); } else if (value is IExternalizable) { PutU8((byte)DataType.EXT); PutExt((IExternalizable)value); } else { PutU8((byte)DataType.NA); } } #endregion #region _集合类型_ public void PutUTFArray(string[] array) { if (array == null) { PutS32(-1); } else { int len = array.Length; if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } PutS32(len); for (int i = 0; i < len; i++) { this.PutUTF(array[i]); } } } public void PutUTFList(IList list) { if (list == null) { PutS32(-1); } else { int len = list.Count; if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } PutS32(len); for (int i = 0; i < len; i++) { this.PutUTF(list[i]); } } } public void PutArray(T[] array, PutData action) { if (array == null) { PutS32(-1); } else { int len = array.Length; if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } PutS32(len); for (int i = 0; i < len; i++) { action.Invoke(array[i]); } } } public void PutList(IList list, PutData action) { if (list == null) { PutS32(-1); } else { int len = list.Count; if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } PutS32(len); for (int i = 0; i < len; i++) { action.Invoke(list[i]); } } } public void PutMap(IDictionary map, PutData k_action, PutData v_action) { if (map == null) { PutS32(-1); } else { int len = map.Count; if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } this.PutS32(len); foreach (var kv in map) { k_action.Invoke(kv.Key); v_action.Invoke(kv.Value); } } } /// /// 不包括消息头,列表中元素必须保证类型一致 /// public void PutStructArray(T[] array) where T : IExternalizable { if (array == null) { PutS32(-1); } else { int len = array.Length; if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } this.PutS32(array.Length); for (int i = 0; i < array.Length; i++) { array[i].WriteExternal(this); } } } /// /// 不包括消息头,列表中元素必须保证类型一致 /// public void PutStructList(IList array) where T : IExternalizable { if (array == null) { PutS32(-1); } else { int len = array.Count; if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } this.PutS32(array.Count); for (int i = 0; i < array.Count; i++) { array[i].WriteExternal(this); } } } /// /// 不包括消息头,列表中元素必须保证类型一致 /// public void PutExtArray(T[] array) where T : IExternalizable { if (array == null) { PutS32(-1); } else { int len = array.Length; if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } this.PutS32(array.Length); for (int i = 0; i < array.Length; i++) { array[i].WriteExternal(this); } } } /// /// 不包括消息头,列表中元素必须保证类型一致 /// public void PutExtList(IList array) where T : IExternalizable { if (array == null) { PutS32(-1); } else { int len = array.Count; if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } this.PutS32(array.Count); for (int i = 0; i < array.Count; i++) { array[i].WriteExternal(this); } } } #endregion } public abstract class IInputStream : IOStream { protected static System.Text.UTF8Encoding utfenc = new System.Text.UTF8Encoding(false); public IInputStream(IExternalizableFactory factory) { this.Factory = factory; } public IExternalizableFactory Factory { get; private set; } #region _Abstract_ public abstract byte[] GetBytes(); public abstract void GetRawData(byte[] buff, int offset, int count); public abstract bool GetBool(); public abstract byte GetU8(); public abstract sbyte GetS8(); public abstract ushort GetU16(); public abstract short GetS16(); public abstract uint GetU32(); public abstract int GetS32(); public abstract ulong GetU64(); public abstract long GetS64(); public abstract float GetF32(); public abstract double GetF64(); public abstract char GetUnicode(); public abstract string GetUTF(); #endregion #region _基础类型_ /// /// 写入可变长度32位 /// public UInt32 GetVU32() { return (UInt32)GetVU64(); } /// /// 写入可变长度32位 /// public Int32 GetVS32() { return (Int32)GetVS64(); } /// /// 写入可变长度64位 /// public Int64 GetVS64() { ulong m = GetVU64(); long v = (long)(m >> 1); if (m % 2 == 1) { return -v; } else { return v; } } /// /// 写入可变长度64位 /// public UInt64 GetVU64() { UInt64 value = 0; UInt64 b = 0; for (int i = 0; i <= 70; i += 7) { b = GetU8(); value |= ((b & 0x7F) << i); if ((b & 0x80) == 0) break; } return value; } public T GetEnum8() { byte u8 = GetU8(); if (Enum.IsDefined(typeof(T), u8)) { return (T)Enum.ToObject(typeof(T), u8); } return default(T); } public T GetEnum32() { int s32 = GetS32(); if (Enum.IsDefined(typeof(T), s32)) { return (T)Enum.ToObject(typeof(T), s32); } return default(T); } #endregion #region _对象类型_ public T GetExt() where T : IExternalizable, new() { int typeID = GetS32(); if (typeID != 0) { Type type = Factory.GetType(typeID); if (type != null) { T any = (T)Activator.CreateInstance(type); any.ReadExternal(this); return any; } else { throw new IOException("Can Not Resolve IExternalizable Message : 0x" + typeID.ToString("X")); } } return default(T); } public T GetExt(T ret) where T : IExternalizable { int typeID = GetS32(); if (typeID != 0) { Type type = Factory.GetType(typeID); if (type == null) { throw new IOException("Can Not Resolve IExternalizable Message : 0x" + typeID.ToString("X")); } if (!type.IsInstanceOfType(ret)) { throw new IOException("type can't match:" + type + "->" + ret.GetType()); } else { ret.ReadExternal(this); return ret; } } return default(T); } public IExternalizable GetExtAny() { int typeID = GetS32(); if (typeID != 0) { Type type = Factory.GetType(typeID); if (type != null) { IExternalizable any = (IExternalizable)Activator.CreateInstance(type); any.ReadExternal(this); return any; } else { throw new IOException("Can Not Resolve IExternalizable Message : 0x" + typeID.ToString("X")); } } return null; } public T GetXml2Obj(Action error = null) { byte[] data = GetBytes(); if (data != null && data.Length > 0) { string xml = CUtils.UTF8.GetString(data); XmlDocument x = XmlUtil.FromString(xml); T ret = (T)XmlUtil.XmlToObject(x, error); return ret; } return default(T); } /// /// 自动检测类型 /// /// public object GetData(out DataType type) { byte dt = GetU8(); if (Enum.IsDefined(typeof(DataType), dt)) { type = (DataType)dt; switch (type) { case DataType.U8: return GetU8(); case DataType.S8: return GetS8(); case DataType.U16: return GetU16(); case DataType.S16: return GetS16(); case DataType.U32: return GetU32(); case DataType.S32: return GetS32(); case DataType.U64: return GetU64(); case DataType.S64: return GetS64(); case DataType.F32: return GetF32(); case DataType.F64: return GetF64(); case DataType.UC: return GetUnicode(); case DataType.UTF: return GetUTF(); case DataType.EXT: return GetExtAny(); } } type = DataType.NA; return null; } public object GetData() { byte dt = GetU8(); if (Enum.IsDefined(typeof(DataType), dt)) { DataType type = (DataType)dt; switch (type) { case DataType.U8: return GetU8(); case DataType.S8: return GetS8(); case DataType.U16: return GetU16(); case DataType.S16: return GetS16(); case DataType.U32: return GetU32(); case DataType.S32: return GetS32(); case DataType.U64: return GetU64(); case DataType.S64: return GetS64(); case DataType.F32: return GetF32(); case DataType.F64: return GetF64(); case DataType.UC: return GetUnicode(); case DataType.UTF: return GetUTF(); case DataType.EXT: return GetExtAny(); } } return null; } #endregion #region _集合类型_ public string[] GetUTFArray() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; string[] ret = new string[len]; for (int i = 0; i < len; i++) { ret[i] = GetUTF(); } return ret; } public T[] GetArray(GetData action) { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; T[] ret = new T[len]; for (int i = 0; i < len; i++) { T d = action.Invoke(); ret[i] = d; } return ret; } /// /// 不包括消息头,列表中元素必须保证类型一致 /// public T[] GetStructArray() where T : IExternalizable, new() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; T[] array = new T[len]; for (int i = 0; i < len; i++) { array[i].ReadExternal(this); } return array; } /// /// 不包括消息头,列表中元素必须保证类型一致 /// public T[] GetExtArray() where T : IExternalizable, new() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; T[] array = new T[len]; for (int i = 0; i < len; i++) { array[i] = new T(); array[i].ReadExternal(this); } return array; } public List GetUTFList() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; List ret = new List(len); for (int i = 0; i < len; i++) { string d = GetUTF(); ret.Add(d); } return ret; } public List GetList(GetData action) { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; List ret = new List(len); for (int i = 0; i < len; i++) { T d = action.Invoke(); ret.Add(d); } return ret; } public List GetListAny() where T : IExternalizable { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; List ret = new List(len); for (int i = 0; i < len; i++) { IExternalizable ext = GetExtAny(); if (ext != null) { ret.Add((T)ext); } } return ret; } /// /// 不包括消息头,列表中元素必须保证类型一致 /// public List GetStructList() where T : IExternalizable, new() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; List list = new List(); for (int i = 0; i < len; i++) { T item = new T(); item.ReadExternal(this); list.Add(item); } return list; } /// /// 不包括消息头,列表中元素必须保证类型一致 /// public List GetExtList() where T : IExternalizable, new() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; List list = new List(); for (int i = 0; i < len; i++) { T item = new T(); item.ReadExternal(this); list.Add(item); } return list; } //-------------------------------------------------------------------------------------------- public L GetGenericUTFList() where L : class, IList, new() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; var ret = new L(); for (int i = 0; i < len; i++) { string d = GetUTF(); ret.Add(d); } return ret; } public L GetGenericList(GetData action) where L : class, IList, new() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; L ret = new L(); for (int i = 0; i < len; i++) { T d = action.Invoke(); ret.Add(d); } return ret; } public L GetGenericListAny() where T : IExternalizable where L : class, IList, new() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; var ret = new L(); for (int i = 0; i < len; i++) { IExternalizable ext = GetExtAny(); if (ext != null) { ret.Add((T)ext); } } return ret; } /// /// 不包括消息头,列表中元素必须保证类型一致 /// public L GetGenericStructList() where T : struct, IExternalizable where L : class, IList, new() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; var list = new L(); for (int i = 0; i < len; i++) { T item = new T(); item.ReadExternal(this); list.Add(item); } return list; } /// /// 不包括消息头,列表中元素必须保证类型一致 /// public L GetGenericExtList() where T : IExternalizable, new() where L : class, IList, new() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; var list = new L(); for (int i = 0; i < len; i++) { T item = new T(); item.ReadExternal(this); list.Add(item); } return list; } //-------------------------------------------------------------------------------------------- public HashMap GetMap(GetData k_action, GetData v_action) { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; HashMap ret = new HashMap(len); for (int i = 0; i < len; i++) { K k = k_action.Invoke(); V v = v_action.Invoke(); ret[k] = v; } return ret; } public M GetGenericMap(GetData k_action, GetData v_action) where M : class, IDictionary, new() { int len = GetS32(); if (len > ARRAY_LIMIT) { throw new IOException("Collection overflow : " + len + " > " + ARRAY_LIMIT); } if (len < 0) return null; M ret = new M(); for (int i = 0; i < len; i++) { K k = k_action.Invoke(); V v = v_action.Invoke(); ret[k] = v; } return ret; } //-------------------------------------------------------------------------------------------- #endregion } }