必须填写至少10个字的日志
nnhy 编写于 2012-07-27 18:48:21
X
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using NewLife.Reflection;

namespace NewLife.Serialization
{
    /// <summary>写入器基类</summary>
    /// <remarks>
    /// 序列化框架的核心思想:基本类型直接写入,自定义类型反射得到成员,逐层递归写入!详见<see cref="IReaderWriter" />
    /// 
    /// 序列化框架的处理顺序为:<see cref="IAccessor" />接口 => <see cref="OnObjectWriting" />事件 => 扩展类型 => <see cref="WriteValue(Object)" />基础类型 => <see cref="WriteDictionary" />字典 => <see cref="WriteEnumerable" />枚举 => <see cref="WriteSerializable" />序列化接口 => <see cref="WriteCustomObject" />自定义对象 => <see cref="WriteUnKnown" />未知类型 => <see cref="OnObjectWrited" />事件
    /// 
    /// 序列化对象时只能调用<see cref="WriteObject(Object)" />方法,其它所有方法(包括所有Write重载)仅用于内部写入或者自定义序列化时使用。
    /// </remarks>
    /// <typeparam name="TSettings">设置类</typeparam>
    public abstract class WriterBase<TSettings> : ReaderWriterBase<TSettings>, IWriter where TSettings : ReaderWriterSetting, new()
    {
        #region 基元类型
        #region 字节
        /// <summary>将一个无符号字节写入</summary>
        /// <param name="value">要写入的无符号字节。</param>
        public abstract void Write(Byte value);

        /// <summary>将字节数组写入,如果设置了UseSize,则先写入数组长度。</summary>
        /// <param name="buffer">包含要写入的数据的字节数组。</param>
        public virtual void Write(byte[] buffer)
        {
            if (buffer == null)
            {
                WriteSize(0);
                return;
            }

            WriteSize(buffer.Length);
            Write(buffer, 0, buffer.Length);
        }

        /// <summary>将一个有符号字节写入当前流,并将流的位置提升 1 个字节。</summary>
        /// <param name="value">要写入的有符号字节。</param>
        //[CLSCompliant(false)]
        public virtual void Write(sbyte value) { Write((Byte)value); }

        /// <summary>将字节数组部分写入当前流,不写入数组长度。</summary>
        /// <param name="buffer">包含要写入的数据的字节数组。</param>
        /// <param name="index">buffer 中开始写入的起始点。</param>
        /// <param name="count">要写入的字节数。</param>
        public virtual void Write(byte[] buffer, int index, int count)
        {
            if (buffer == null || buffer.Length < 1 || count <= 0 || index >= buffer.Length) return;

            for (int i = 0; i < count && index + i < buffer.Length; i++)
            {
                Write(buffer[index + i]);
            }
        }

        /// <summary>写入字节数组,自动计算长度</summary>
        /// <param name="buffer"></param>
        /// <param name="count"></param>
        private void Write(Byte[] buffer, Int32 count)
        {
            if (buffer == null) return;

            if (count < 0 || count > buffer.Length) count = buffer.Length;

            Write(buffer, 0, count);
        }
        #endregion

        #region 有符号整数
        /// <summary>写入整数的字节数组,某些写入器(如二进制写入器)可能需要改变字节顺序</summary>
        /// <param name="buffer"></param>
        protected virtual void WriteIntBytes(Byte[] buffer) { Write(buffer, -1); }

        /// <summary>将 2 字节有符号整数写入当前流,并将流的位置提升 2 个字节。</summary>
        /// <param name="value">要写入的 2 字节有符号整数。</param>
        public virtual void Write(short value) { WriteIntBytes(BitConverter.GetBytes(value)); }

        /// <summary>将 4 字节有符号整数写入当前流,并将流的位置提升 4 个字节。</summary>
        /// <param name="value">要写入的 4 字节有符号整数。</param>
        public virtual void Write(int value) { WriteIntBytes(BitConverter.GetBytes(value)); }

        /// <summary>将 8 字节有符号整数写入当前流,并将流的位置提升 8 个字节。</summary>
        /// <param name="value">要写入的 8 字节有符号整数。</param>
        public virtual void Write(long value) { WriteIntBytes(BitConverter.GetBytes(value)); }
        #endregion

        #region 无符号整数
        /// <summary>将 2 字节无符号整数写入当前流,并将流的位置提升 2 个字节。</summary>
        /// <param name="value">要写入的 2 字节无符号整数。</param>
        //[CLSCompliant(false)]
        public virtual void Write(ushort value) { Write((Int16)value); }

        /// <summary>将 4 字节无符号整数写入当前流,并将流的位置提升 4 个字节。</summary>
        /// <param name="value">要写入的 4 字节无符号整数。</param>
        //[CLSCompliant(false)]
        public virtual void Write(uint value) { Write((Int32)value); }

        /// <summary>将 8 字节无符号整数写入当前流,并将流的位置提升 8 个字节。</summary>
        /// <param name="value">要写入的 8 字节无符号整数。</param>
        //[CLSCompliant(false)]
        public virtual void Write(ulong value) { Write((Int64)value); }
        #endregion

        #region 浮点数
        /// <summary>将 4 字节浮点值写入当前流,并将流的位置提升 4 个字节。</summary>
        /// <param name="value">要写入的 4 字节浮点值。</param>
        public virtual void Write(float value) { Write(BitConverter.GetBytes(value), -1); }

        /// <summary>将 8 字节浮点值写入当前流,并将流的位置提升 8 个字节。</summary>
        /// <param name="value">要写入的 8 字节浮点值。</param>
        public virtual void Write(double value) { Write(BitConverter.GetBytes(value), -1); }
        #endregion

        #region 字符串
        /// <summary>将 Unicode 字符写入当前流,并根据所使用的 Encoding 和向流中写入的特定字符,提升流的当前位置。</summary>
        /// <param name="ch">要写入的非代理项 Unicode 字符。</param>
        public virtual void Write(char ch) { Write(Convert.ToByte(ch)); }

        /// <summary>将字符数组写入当前流,并根据所使用的 Encoding 和向流中写入的特定字符,提升流的当前位置。</summary>
        /// <param name="chars">包含要写入的数据的字符数组。</param>
        public virtual void Write(char[] chars) { Write(chars, 0, chars == null ? 0 : chars.Length); }

        /// <summary>将字符数组部分写入当前流,并根据所使用的 Encoding(可能还根据向流中写入的特定字符),提升流的当前位置。</summary>
        /// <param name="chars">包含要写入的数据的字符数组。</param>
        /// <param name="index">chars 中开始写入的起始点。</param>
        /// <param name="count">要写入的字符数。</param>
        public virtual void Write(char[] chars, int index, int count)
        {
            if (chars == null)
            {
                WriteSize(0);
                return;
            }

            if (chars.Length < 1 || count <= 0 || index >= chars.Length)
            {
                WriteSize(0);
                return;
            }

            // 先用写入字节长度
            Byte[] buffer = Settings.Encoding.GetBytes(chars, index, count);
            Write(buffer);
        }

        /// <summary>写入字符串</summary>
        /// <param name="value">要写入的值。</param>
        public virtual void Write(string value) { Write(value == null ? null : value.ToCharArray()); }
        #endregion

        #region 其它
        /// <summary>将单字节 Boolean 值写入</summary>
        /// <param name="value">要写入的 Boolean 值</param>
        public virtual void Write(Boolean value) { Write((Byte)(value ? 1 : 0)); }

        /// <summary>将一个十进制值写入当前流,并将流位置提升十六个字节。</summary>
        /// <param name="value">要写入的十进制值。</param>
        public virtual void Write(decimal value)
        {
            Int32[] data = Decimal.GetBits(value);
            for (int i = 0; i < data.Length; i++)
            {
                Write(data[i]);
            }
        }

        /// <summary>将一个时间日期写入</summary>
        /// <param name="value"></param>
        public virtual void Write(DateTime value) { Write(Settings.ConvertDateTimeToInt64(value)); }
        #endregion
        #endregion

        #region 值类型
        /// <summary>写入值类型</summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public Boolean WriteValue(Object value) { return WriteValue(value, null); }

        /// <summary>写入值类型,只能识别基础类型,对于不能识别的类型,方法返回false</summary>
        /// <param name="value">要写入的对象</param>
        /// <param name="type">要写入的对象类型</param>
        /// <returns>是否写入成功</returns>
        protected virtual Boolean WriteValue(Object value, Type type)
        {
            if (type == null)
            {
                if (value == null) return false;
                type = value.GetType();
            }

            TypeCode code = Type.GetTypeCode(type);
            switch (code)
            {
                case TypeCode.Boolean:
                    Write((Boolean)value);
                    return true;
                case TypeCode.Byte:
                    Write((Byte)value);
                    return true;
                case TypeCode.Char:
                    Write((Char)value);
                    return true;
                case TypeCode.DBNull:
                    Write((Byte)0);
                    return true;
                case TypeCode.DateTime:
                    Write((DateTime)value);
                    return true;
                case TypeCode.Decimal:
                    Write((Decimal)value);
                    return true;
                case TypeCode.Double:
                    Write((Double)value);
                    return true;
                case TypeCode.Empty:
                    Write((Byte)0);
                    return true;
                case TypeCode.Int16:
                    Write((Int16)value);
                    return true;
                case TypeCode.Int32:
                    Write((Int32)value);
                    return true;
                case TypeCode.Int64:
                    Write((Int64)value);
                    return true;
                case TypeCode.Object:
                    break;
                case TypeCode.SByte:
                    Write((SByte)value);
                    return true;
                case TypeCode.Single:
                    Write((Single)value);
                    return true;
                case TypeCode.String:
                    Write((String)value);
                    return true;
                case TypeCode.UInt16:
                    Write((UInt16)value);
                    return true;
                case TypeCode.UInt32:
                    Write((UInt32)value);
                    return true;
                case TypeCode.UInt64:
                    Write((UInt64)value);
                    return true;
                default:
                    break;
            }

            return false;
        }
        #endregion

        #region 字典
        /// <summary>写入枚举类型数据</summary>
        /// <param name="value">枚举数据</param>
        /// <returns>是否写入成功</returns>
        public Boolean Write(IDictionary value) { return WriteDictionary(value, null, WriteMember); }

        /// <summary>写入字典类型数据</summary>
        /// <param name="value">字典数据</param>
        /// <param name="type">要写入的对象类型</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否写入成功</returns>
        public virtual Boolean WriteDictionary(IDictionary value, Type type, WriteObjectCallback callback)
        {
            if (value == null) return true;
            // type = CheckAndWriteType("WriteDictionaryType", value, type);

            // 计算元素类型
            Type keyType = null;
            Type valueType = null;

            // 取得键值类型
            //if (!GetDictionaryEntryType(type, ref keyType, ref valueType)) return false;
            GetDictionaryEntryType(type, ref keyType, ref valueType);

            WriteSize(value.Count);
            if (value.Count == 0) return true;

            //type = value.GetType();
            if (type != null && !typeof(IDictionary).IsAssignableFrom(type)) throw new InvalidOperationException("目标类型不是字典类型!");

            Int32 i = 0;
            foreach (DictionaryEntry item in value)
            {
                Depth++;
                if (!WriteKeyValue(item, keyType, valueType, i++, callback)) return false;
                Depth--;
            }

            return true;
        }

        /// <summary>写入字典项</summary>
        /// <param name="value">对象</param>
        /// <param name="keyType">键类型</param>
        /// <param name="valueType">值类型</param>
        /// <param name="index">成员索引</param>
        /// <param name="callback">使用指定委托方法处理复杂数据</param>
        /// <returns>是否写入成功</returns>
        protected Boolean WriteKeyValue(DictionaryEntry value, Type keyType, Type valueType, Int32 index, WriteObjectCallback callback)
        {
            // 写入成员前
            WriteDictionaryEventArgs e = null;
            if (OnDictionaryWriting != null)
            {
                e = new WriteDictionaryEventArgs(value, keyType, valueType, index, callback);

                OnDictionaryWriting(this, e);

                // 事件处理器可能已经成功写入对象
                if (e.Success) return true;

                // 事件里面有可能改变了参数
                value = (DictionaryEntry)e.Value;
                keyType = e.KeyType;
                valueType = e.ValueType;
                index = e.Index;
                callback = e.Callback;
            }

            Boolean rs = OnWriteKeyValue(value, keyType, valueType, index, callback);

            // 写入成员后
            if (OnDictionaryWrited != null)
            {
                if (e == null) e = new WriteDictionaryEventArgs(value, keyType, valueType, index, callback);
                e.Success = rs;

                OnDictionaryWrited(this, e);

                // 事件处理器可以影响结果
                rs = e.Success;
            }

            return rs;
        }

        /// <summary>写入字典项</summary>
        /// <param name="value">对象</param>
        /// <param name="keyType">键类型</param>
        /// <param name="valueType">值类型</param>
        /// <param name="index">成员索引</param>
        /// <param name="callback">使用指定委托方法处理复杂数据</param>
        /// <returns>是否写入成功</returns>
        protected virtual Boolean OnWriteKeyValue(DictionaryEntry value, Type keyType, Type valueType, Int32 index, WriteObjectCallback callback)
        {
            // 如果无法取得字典项类型,则每个键值都单独写入类型
            //keyType = CheckAndWriteType("WriteKeyType", value.Key, keyType);
            if (!WriteObject(value.Key, keyType, callback)) return false;

            // valueType = CheckAndWriteType("WriteValueType", value.Value, valueType);
            if (!WriteObject(value.Value, valueType, callback)) return false;

            return true;
        }

        /// <summary>取得字典的键值类型,默认只支持获取两个泛型参数的字典的键值类型</summary>
        /// <param name="type">字典类型</param>
        /// <param name="keyType">键类型</param>
        /// <param name="valueType">值类型</param>
        /// <returns>是否获取成功,如果失败,则字典读取失败</returns>
        protected virtual Boolean GetDictionaryEntryType(Type type, ref Type keyType, ref Type valueType)
        {
            // 两个泛型参数的泛型
            if (type.IsGenericType)
            {
                Type[] ts = type.GetGenericArguments();
                if (ts != null && ts.Length == 2)
                {
                    keyType = ts[0];
                    valueType = ts[1];

                    return true;
                }
            }

            return false;
        }
        #endregion

        #region 枚举
        /// <summary>写入枚举类型数据</summary>
        /// <param name="value">枚举数据</param>
        /// <returns>是否写入成功</returns>
        public Boolean Write(IEnumerable value) { return WriteEnumerable(value, null, WriteMember); }

        /// <summary>写入枚举数据,复杂类型使用委托方法进行处理</summary>
        /// <param name="value">对象</param>
        /// <param name="type">类型</param>
        /// <param name="callback">使用指定委托方法处理复杂数据</param>
        /// <returns>是否写入成功</returns>
        public virtual Boolean WriteEnumerable(IEnumerable value, Type type, WriteObjectCallback callback)
        {
            if (value == null) return true;

            type = CheckAndWriteType("WriteEnumerableType", value, type);

            //type = value.GetType();
            if (type != null && !typeof(IEnumerable).IsAssignableFrom(type)) throw new InvalidOperationException("目标类型不是枚举类型!");

            // 计算元素类型,如果无法计算,这里不能处理,否则能写不能读(因为不知道元素类型)
            var elementType = TypeX.GetElementType(type);

            //if (elementType == null) return false;

            Int32 i = 0;
            foreach (var item in value)
            {
                Depth++;
                if (!WriteItem(item, elementType, i++, callback)) return false;
                Depth--;
            }
            return true;
        }

        /// <summary>写入枚举项</summary>
        /// <param name="value">对象</param>
        /// <param name="type">元素类型</param>
        /// <param name="index">元素索引</param>
        /// <param name="callback">使用指定委托方法处理复杂数据</param>
        /// <returns>是否写入成功</returns>
        protected Boolean WriteItem(Object value, Type type, Int32 index, WriteObjectCallback callback)
        {
            // 写入成员前
            WriteItemEventArgs e = null;
            if (OnItemWriting != null)
            {
                e = new WriteItemEventArgs(value, type, index, callback);

                OnItemWriting(this, e);

                // 事件处理器可能已经成功写入对象
                if (e.Success) return true;

                // 事件里面有可能改变了参数
                value = e.Value;
                type = e.Type;
                index = e.Index;
                callback = e.Callback;
            }

            Boolean rs = OnWriteItem(value, type, index, callback);

            // 写入成员后
            if (OnItemWrited != null)
            {
                if (e == null) e = new WriteItemEventArgs(value, type, index, callback);
                e.Success = rs;

                OnItemWrited(this, e);

                // 事件处理器可以影响结果
                rs = e.Success;
            }

            return rs;
        }

        /// <summary>写入枚举项</summary>
        /// <param name="value">对象</param>
        /// <param name="type">元素类型</param>
        /// <param name="index">元素索引</param>
        /// <param name="callback">使用指定委托方法处理复杂数据</param>
        /// <returns>是否写入成功</returns>
        protected virtual Boolean OnWriteItem(Object value, Type type, Int32 index, WriteObjectCallback callback)
        {
            // 如果无法取得元素类型,则每个元素都单独写入类型
            // type = CheckAndWriteType("WriteItemType", value, type);
            return WriteObject(value, type, callback);
        }
        #endregion

        #region 序列化接口
        /// <summary>写入实现了可序列化接口的对象</summary>
        /// <param name="value">要写入的对象</param>
        /// <param name="type">要写入的对象类型</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否写入成功</returns>
        public virtual Boolean WriteSerializable(Object value, Type type, WriteObjectCallback callback)
        {
            if (!typeof(ISerializable).IsAssignableFrom(type)) return false;

            WriteLog("WriteSerializable", type.Name);

            return WriteCustomObject(value, type, callback);
        }
        #endregion

        #region 未知对象
        /// <summary>写入未知对象(其它所有方法都无法识别的对象),采用BinaryFormatter或者XmlSerialization</summary>
        /// <param name="value">要写入的对象</param>
        /// <param name="type">要写入的对象类型</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否写入成功</returns>
        public virtual Boolean WriteUnKnown(Object value, Type type, WriteObjectCallback callback)
        {
            WriteLog("WriteUnKnown", type.Name);

            // 调用.Net的二进制序列化来解决剩下的事情
            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            bf.Serialize(ms, value);
            ms.Position = 0;
            Write(ms.ToArray());

            return true;
        }
        #endregion

        #region 扩展处理类型
        /// <summary>扩展写入,反射查找合适的写入方法</summary>
        /// <param name="value"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        protected virtual Boolean WriteX(Object value, Type type)
        {
            if (type == typeof(Byte[]))
            {
                Write((Byte[])value);
                return true;
            }
            if (type == typeof(Char[]))
            {
                Write((Char[])value);
                return true;
            }

            //! 所有扩展类型的写入,分为Write和OnWrite两部分,Write供外部独立调用,单独提供对象引用,而OnWrite不写对象引用
            if (type == typeof(Guid))
            {
                OnWrite((Guid)value);
                return true;
            }
            if (type == typeof(IPAddress))
            {
                OnWrite((IPAddress)value);
                return true;
            }
            if (type == typeof(IPEndPoint))
            {
                OnWrite((IPEndPoint)value);
                return true;
            }
            if (typeof(Type).IsAssignableFrom(type))
            {
                OnWrite((Type)value);
                return true;
            }

            return false;
        }

        /// <summary>写入Guid</summary>
        /// <param name="value"></param>
        public virtual void Write(Guid value) { if (!WriteObjRef(value))  OnWrite(value); }

        /// <summary>写入Guid</summary>
        /// <param name="value"></param>
        protected virtual void OnWrite(Guid value) { Write(((Guid)value).ToByteArray(), -1); }

        /// <summary>写入IPAddress</summary>
        /// <param name="value"></param>
        public virtual void Write(IPAddress value) { if (!WriteObjRef(value)) OnWrite(value); }

        /// <summary>写入IPAddress</summary>
        /// <param name="value"></param>
        protected virtual void OnWrite(IPAddress value) { Write((value as IPAddress).GetAddressBytes()); }

        /// <summary>写入IPEndPoint</summary>
        /// <param name="value"></param>
        public virtual void Write(IPEndPoint value) { if (!WriteObjRef(value)) OnWrite(value); }

        /// <summary>写入IPEndPoint</summary>
        /// <param name="value"></param>
        protected virtual void OnWrite(IPEndPoint value)
        {
            //! 直接调用OnWrite,不写对象引用,将来可能得考虑写对象引用
            OnWrite(value.Address);
            //// 端口实际只占2字节
            //Write((UInt16)value.Port);
            Write(value.Port);
        }

        /// <summary>写入Type</summary>
        /// <param name="value"></param>
        public void Write(Type value) { if (!WriteObjRef(value))  OnWrite(value); }

        /// <summary>写入Type</summary>
        /// <param name="value"></param>
        protected virtual void OnWrite(Type value)
        {
            Depth++;
            WriteLog("WriteType", value.FullName);

            // 分离出去,便于重载,而又能有效利用对象引用
            OnWriteType(value);
            Depth--;
        }

        /// <summary>写入Type</summary>
        /// <param name="value"></param>
        protected virtual void OnWriteType(Type value)
        {
            // 尽管使用AssemblyQualifiedName更精确,但是它的长度实在太大了
            if (Settings.UseTypeFullName)
                Write(value.AssemblyQualifiedName);
            else
                Write(value.FullName);
        }

        /// <summary>
        /// 检查对象类型与指定写入类型是否一致,若不一致,则先写入类型,以保证读取的时候能够以正确的类型读取。同时返回对象实际类型。
        /// 若想不写对象类型,可以提前设定精确类型。
        /// </summary>
        /// <param name="action"></param>
        /// <param name="value"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        protected Type CheckAndWriteType(String action, Object value, Type type)
        {
            if (type == null && value == null) return null;

            // 若想不写对象类型,可以提前设定精确类型
            if (!IsExactType(type))
            {
                if (value != null) type = value.GetType();
                WriteLog(action, type.Name);
                WriteObjectType(type);
            }

            return type;
        }

        /// <summary>写对象类型</summary>
        /// <param name="type"></param>
        protected virtual void WriteObjectType(Type type) { Write(type); }
        #endregion

        #region 复杂对象
        /// <summary>主要入口方法。把对象写入数据流</summary>
        /// <param name="value">对象</param>
        /// <returns>是否写入成功</returns>
        public Boolean WriteObject(Object value) { return WriteObject(value, null, WriteMember); }

        /// <summary>主要入口方法。把目标对象指定成员写入数据流,处理基础类型、特殊类型、基础类型数组、特殊类型数组,通过委托方法处理成员</summary>
        /// <param name="value">要写入的对象</param>
        /// <param name="type">要写入的对象类型</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否写入成功</returns>
        public Boolean WriteObject(Object value, Type type, WriteObjectCallback callback)
        {
            if (type == null && value != null) type = value.GetType();
            if (callback == null) callback = WriteMember;

            // 检查IAcessor接口
            IAccessor accessor = value as IAccessor;
            if (accessor != null && accessor.Write(this)) return true;

            Boolean rs = WriteObjectWithEvent(value, type, callback);

            // 检查IAcessor接口
            if (accessor != null) rs = accessor.WriteComplete(this, rs);

            return rs;
        }

        Boolean WriteObjectWithEvent(Object value, Type type, WriteObjectCallback callback)
        {
            // 事件
            WriteObjectEventArgs e = null;
            if (OnObjectWriting != null)
            {
                e = new WriteObjectEventArgs(value, type, callback);

                OnObjectWriting(this, e);

                // 事件处理器可能已经成功写入对象
                if (e.Success) return true;

                // 事件里面有可能改变了参数
                value = e.Value;
                type = e.Type;
                callback = e.Callback;
            }

            Boolean rs = OnWriteObject(value, type, callback);

            // 事件
            if (OnObjectWrited != null)
            {
                if (e == null) e = new WriteObjectEventArgs(value, type, callback);
                e.Success = rs;

                OnObjectWrited(this, e);

                // 事件处理器可以影响结果
                rs = e.Success;
            }

            return rs;
        }

        /// <summary>把目标对象指定成员写入数据流,处理基础类型、特殊类型、基础类型数组、特殊类型数组,通过委托方法处理成员</summary>
        /// <param name="value">要写入的对象</param>
        /// <param name="type">要写入的对象类型</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否写入成功</returns>
        protected virtual Boolean OnWriteObject(Object value, Type type, WriteObjectCallback callback)
        {
            //! 2011-05-27 17:33
            //! 精确类型,直接写入值
            //! 未知类型,写对象引用,写类型,写对象

            if (IsExactType(type))
            {
                // 基本类型
                if (WriteValue(value, type)) return true;

                // 写入对象引用
                if (WriteObjRef(value)) return true;

                // 扩展类型
                if (WriteX(value, type)) return true;

                // 写入引用对象
                if (WriteRefObject(value, type, callback)) return true;
            }
            else
            {
                // 写入对象引用
                if (WriteObjRef(value)) return true;

                // 写对象类型时增加缩进,避免写顶级对象类型的对象引用时无法写入(Depth=1的对象是不写对象引用的)
                Depth++;
                type = CheckAndWriteType("WriteObjectType", value, type);
                Depth--;

                // 基本类型
                if (WriteValue(value, type)) return true;

                // 扩展类型
                if (WriteX(value, type)) return true;

                // 写入引用对象
                if (WriteRefObject(value, type, callback)) return true;
            }

            return true;
        }

        /// <summary>写入引用对象</summary>
        /// <param name="value">要写入的对象</param>
        /// <param name="type">要写入的对象类型</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否写入成功</returns>
        protected virtual Boolean WriteRefObject(Object value, Type type, WriteObjectCallback callback)
        {
            // 字典
            if (typeof(IDictionary).IsAssignableFrom(type))
            {
                WriteLog("WriteDictionary", type.Name);

                if (WriteDictionary(value as IDictionary, type, callback)) return true;
            }

            // 枚举
            if (typeof(IEnumerable).IsAssignableFrom(type))
            {
                WriteLog("WriteEnumerable", type.Name);

                if (WriteEnumerable(value as IEnumerable, type, callback)) return true;
            }

            // 可序列化接口
            if (WriteSerializable(value, type, callback)) return true;

            // 复杂类型,处理对象成员
            if (WriteCustomObject(value, type, callback)) return true;

            return WriteUnKnown(value, type, callback);
        }

        List<Object> objRefs = new List<Object>();

        /// <summary>写入对象引用。</summary>
        /// <param name="value">对象</param>
        /// <returns>是否写入成功</returns>
        public Boolean WriteObjRef(Object value)
        {
            if (!Settings.UseObjRef) return false;

            if (value == null)
            {
                WriteLog("WriteObjRef", "null");

                // 顶级不需要
                if (Depth > 1) OnWriteObjRefIndex(0);
                return true;
            }

            // 在对象引用集合中找该对象
            Int32 index = objRefs.IndexOf(value);

            // 如果没找到,添加,返回false,通知上层继续处理
            if (index < 0)
            {
                objRefs.Add(value);

                WriteLog("AddObjRef", objRefs.Count, value.ToString(), value.GetType().Name);

                // 写入引用计数
                if (Depth > 1) OnWriteObjRefIndex(objRefs.Count);

                return false;
            }

            WriteLog("WriteObjRef", index + 1, value.ToString(), value.GetType().Name);

            // 如果找到,写入对象引用计数,返回true,通知上层不要再处理该对象,避免重写写入对象
            OnWriteObjRefIndex(index + 1);

            return true;
        }

        /// <summary>写对象引用计数</summary>
        /// <param name="index"></param>
        protected virtual void OnWriteObjRefIndex(Int32 index) { Write(index); }
        #endregion

        #region 自定义对象
        /// <summary>写自定义对象</summary>
        /// <param name="value">要写入的对象</param>
        /// <param name="type">要写入的对象类型</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否写入成功</returns>
        public virtual Boolean WriteCustomObject(Object value, Type type, WriteObjectCallback callback)
        {
            if (value == null) return true;
            if (callback == null) callback = WriteMember;

            Object old = CurrentObject;
            CurrentObject = old;

            try
            {
                IObjectMemberInfo[] mis = GetMembers(type, value);
                if (mis == null || mis.Length < 1) return true;

                // 调试输出成员列表
                if (Debug) ShowMembers("WriteCustomObject", mis);

                for (int i = 0; i < mis.Length; i++)
                {
                    Depth++;
                    // 基础类型输出日志时,同时输出值,更直观
                    if (Type.GetTypeCode(mis[i].Type) == TypeCode.Object)
                        WriteLog("WriteMember", mis[i].Name, mis[i].Type.Name);
                    else
                        WriteLog("WriteMember", mis[i].Name, mis[i].Type.Name, mis[i][value]);

                    if (!WriteMember(value, mis[i].Type, mis[i], i, callback)) return false;
                    Depth--;
                }

                return true;
            }
            finally { CurrentObject = old; }
        }

        /// <summary>写入对象成员</summary>
        /// <param name="value">要写入的对象</param>
        /// <param name="type">要写入的对象类型</param>
        /// <param name="member">成员</param>
        /// <param name="index">成员索引</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否写入成功</returns>
        public Boolean WriteMember(Object value, Type type, IObjectMemberInfo member, Int32 index, WriteObjectCallback callback)
        {
            if (callback == null) callback = WriteMember;

            IObjectMemberInfo old = CurrentMember;
            CurrentMember = member;

#if !DEBUG
            try
#endif
            {
                // 写入成员前
                WriteMemberEventArgs e = null;
                if (OnMemberWriting != null)
                {
                    e = new WriteMemberEventArgs(value, type, member, index, callback);

                    OnMemberWriting(this, e);

                    // 事件处理器可能已经成功写入对象
                    if (e.Success)
                    {
                        CurrentMember = old;
                        return true;
                    }

                    // 事件里面有可能改变了参数
                    value = e.Value;
                    type = e.Type;
                    member = e.Member;
                    index = e.Index;
                    callback = e.Callback;
                }

                Boolean rs = OnWriteMember(value, type, member, index, callback);

                // 写入成员后
                if (OnMemberWrited != null)
                {
                    e = new WriteMemberEventArgs(value, type, member, index, callback);
                    e.Success = rs;

                    OnMemberWrited(this, e);

                    // 事件处理器可以影响结果
                    rs = e.Success;
                }

                CurrentMember = old;

                return rs;
            }
#if !DEBUG
            catch (Exception ex)
            {
                throw new XSerializationException(member, ex);
            }
#endif
        }

        /// <summary>写入对象成员</summary>
        /// <param name="value">要写入的对象</param>
        /// <param name="type">要写入的对象类型</param>
        /// <param name="member">成员</param>
        /// <param name="index">成员索引</param>
        /// <param name="callback">处理成员的方法</param>
        /// <returns>是否写入成功</returns>
        protected virtual Boolean OnWriteMember(Object value, Type type, IObjectMemberInfo member, Int32 index, WriteObjectCallback callback) { return callback(this, member[value], type, callback); }

        private static Boolean WriteMember(IWriter writer, Object value, Type type, WriteObjectCallback callback) { return writer.WriteObject(value, type, callback); }
        #endregion

        #region 事件
        /// <summary>写对象前触发。</summary>
        public event EventHandler<WriteObjectEventArgs> OnObjectWriting;

        /// <summary>写对象后触发。</summary>
        public event EventHandler<WriteObjectEventArgs> OnObjectWrited;

        /// <summary>写成员前触发。</summary>
        public event EventHandler<WriteMemberEventArgs> OnMemberWriting;

        /// <summary>写成员后触发。</summary>
        public event EventHandler<WriteMemberEventArgs> OnMemberWrited;

        /// <summary>写字典项前触发。</summary>
        public event EventHandler<WriteDictionaryEventArgs> OnDictionaryWriting;

        /// <summary>写字典项后触发。</summary>
        public event EventHandler<WriteDictionaryEventArgs> OnDictionaryWrited;

        /// <summary>写枚举项前触发。</summary>
        public event EventHandler<WriteItemEventArgs> OnItemWriting;

        /// <summary>写枚举项后触发。</summary>
        public event EventHandler<WriteItemEventArgs> OnItemWrited;
        #endregion

        #region 方法
        /// <summary>写入大小</summary>
        /// <param name="size"></param>
        public void WriteSize(Int32 size)
        {
            if (!UseSize) return;

            WriteLog("WriteSize", size);

            OnWriteSize(size);
        }

        /// <summary>写入大小</summary>
        /// <param name="size"></param>
        protected virtual void OnWriteSize(Int32 size)
        {
            switch (Settings.SizeFormat)
            {
                case TypeCode.Int16:
                case TypeCode.UInt16:
                    Write((Int16)size);
                    break;
                case TypeCode.Int32:
                case TypeCode.UInt32:
                case TypeCode.Int64:
                case TypeCode.UInt64:
                default:
                    Write(size);
                    break;
            }
        }

        /// <summary>写入长度。多维数组用</summary>
        /// <param name="lengths"></param>
        protected virtual void WriteLengths(string lengths)
        {
            //if (!UseSize) return;

            WriteLog("WriteLengths", lengths);

            Write(lengths);
        }

        /// <summary>刷新缓存中的数据</summary>
        public virtual void Flush() { Stream.Flush(); }

        /// <summary>如果设置了自动刷新缓存,该方面将会调用Flush</summary>
        protected void AutoFlush() { if (Settings.AutoFlush) Flush(); }

        /// <summary>重置</summary>
        public override void Reset()
        {
            objRefs.Clear();

            base.Reset();
        }

        // 耗时且影响数据流,慎用!
        ///// <summary>输出数据转为字节数组。耗时且影响数据流,慎用!</summary>
        ///// <returns></returns>
        //public virtual Byte[] ToArray()
        //{
        //    Flush();

        //    Stream stream = Stream;
        //    if (stream is MemoryStream) return (stream as MemoryStream).ToArray();

        //    if (!stream.CanRead) return null;

        //    // 移动指针到开头
        //    Int64 p = stream.Length;
        //    if (stream.CanSeek) stream.Seek(0, SeekOrigin.Begin);

        //    // 把数据复制出来
        //    var buffer = stream.ReadBytes();
        //    if (stream.CanSeek) stream.Seek(p, SeekOrigin.Begin);

        //    return buffer;
        //}

        // 耗时且影响数据流,慎用!
        ///// <summary>已重载。</summary>
        ///// <returns></returns>
        //public override string ToString()
        //{
        //    Byte[] buffer = ToArray();
        //    if (buffer == null || buffer.Length < 1) return base.ToString();

        //    return Settings.Encoding.GetString(buffer);
        //}
        #endregion
    }
}