/// <summary>
        /// 序列化前触发
        /// </summary>
        /// <param name="context"></param>
        /// <returns>是否允许序列化当前字段或属性</returns>
        protected virtual Boolean OnSerializing(WriteContext context)
        {
            Boolean b = true;

            // 事件由外部动态指定,拥有优先处理权
            if (Serializing != null)
            {
                ProtocolSerializingEventArgs e = new ProtocolSerializingEventArgs(context);
                e.Cancel = false;
                Serializing(this, e);
                b = !e.Cancel;
            }

            IProtocolSerializable custom = context.GetCustomInterface();
            if (custom != null) b = custom.OnSerializing(context);

            return b;
        }
        /// <summary>
        /// 序列化后触发
        /// </summary>
        /// <param name="context"></param>
        protected virtual void OnSerialized(WriteContext context)
        {
            // 事件由外部动态指定,拥有优先处理权
            if (Serialized != null) Serialized(this, new ProtocolSerializedEventArgs(context));

            IProtocolSerializable custom = context.GetCustomInterface();
            if (custom != null) custom.OnSerialized(context);
        }
        void WriteEnumerable(WriteContext context)
        {
            // 先写元素个数
            IEnumerable arr = context.Data as IEnumerable;
            Int32 count = 0;
            foreach (Object item in arr)
            {
                count++;
            }
            // 特性指定了长度,这里就不需要再写入长度了
            if (context.Config.Size <= 0) context.Writer.WriteEncoded(count);

            Int32 n = 0;
            foreach (Object item in arr)
            {
                Type type = null;
                if (item != null) type = item.GetType();
                WriteMember(context.Clone(item, type, type, n++.ToString()) as WriteContext);
            }
        }
        /// <summary>
        /// 把一个对象序列化到指定流中
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="obj"></param>
        public void Serialize(Stream stream, object obj)
        {
            if (obj == null) throw new ArgumentNullException("obj");

            WriteContext context = new WriteContext();
            context.Formatter = this;
            context.Writer = new BinaryWriterX(stream);
            context.Data = obj;
            context.Type = obj.GetType();

            // 树,用于记录分析所到达的位置
            context.Node = new ProtocolTreeNode(null, context.Type);
            context.Node.Context = context;

            //context.Config = FormatterConfig.Default;
            context.Config = Head.Config;

            //RefObjects = null;

            // 使用默认设置写入头部
            if (!Head.Config.NoHead)
            {
                Head.AssemblyName = context.Type.Assembly.FullName;
                Head.TypeName = context.Type.FullName;
                //WriteMember(writer, Head, config, node.Add("Head", Head.GetType()));
                WriteMember(context.Clone(Head, Head.GetType(), null, "Head") as WriteContext);

                //// 只有使用了头部,才使用头部设置信息,否则使用默认设置信息,因为远端需要正确识别数据
                //context.Config = Head.Config;
            }

            // 写入主体
            //WriteMember(writer, obj, config, node.Add("Body", obj.GetType()));
            WriteMember(context.Clone(obj, context.Type, null, "Body") as WriteContext);
        }
        void WriteObjectRef(WriteContext context)
        {
            //// 检测循环引用
            //if (RefObjects == null) RefObjects = new Dictionary<Object, Int32>();

            //if (RefObjects.ContainsKey(context.Data))
            //    throw new InvalidOperationException("检测到循环引用!" + context.Node);

            //RefObjects.Add(context.Data, RefObjects.Count + 1);

            // 写入一个字节表示当前对象不为空
            // 实际上,还可以建立一个只能容纳255个类型的数组,这个字节用于表示类型
            if (!context.Config.UseRefObject && context.Node.Depth > 1 && !context.Config.NotNull) context.Writer.Write((Byte)1);

            Type type = context.Type;
            // 对于对象引用型的字段,需要合并上类上的设置
            context.Config = context.Config.CloneAndMerge(type);

            // 反射得到所有需要序列化的字段或属性
            MemberInfo[] mis = FindAllSerialized(type, context.Config.SerialProperty);
            if (mis != null && mis.Length > 0)
            {
                // 先获取类特性,后获取成员特性,所以,成员特性优先于类特性
                foreach (MemberInfo item in mis)
                {
                    if (item is FieldInfo)
                    {
                        FieldInfo fi = item as FieldInfo;
                        Object obj = FieldInfoX.Create(fi).GetValue(context.Data);
                        type = obj == null ? fi.FieldType : obj.GetType();
                        WriteMember(context.Clone(obj, type, item) as WriteContext);
                    }
                    else
                    {
                        PropertyInfo pi = item as PropertyInfo;
                        Object obj = PropertyInfoX.Create(pi).GetValue(context.Data);
                        type = obj == null ? pi.PropertyType : obj.GetType();
                        WriteMember(context.Clone(obj, type, item) as WriteContext);
                    }
                }
            }
        }
        void WriteArray(WriteContext context)
        {
            // 先写元素个数
            Array arr = context.Data as Array;
            // 特性指定了长度,这里就不需要再写入长度了
            if (context.Config.Size <= 0) context.Writer.WriteEncoded(arr.Length);

            // 特殊处理字节数组
            if (context.Type == typeof(Byte[]))
            {
                context.Writer.Write((Byte[])context.Data);
                return;
            }

            Int32 n = 0;
            foreach (Object item in arr)
            {
                Type type = null;
                if (item != null) type = item.GetType();
                WriteMember(context.Clone(item, type, type, n++.ToString()) as WriteContext);
            }
        }
        private void WriteMemberInternal(WriteContext context)
        {
            BinaryWriterX writer = context.Writer;
            Object data = context.Data;
            Boolean encodeInt = context.Config.EncodeInt;

            // 空数据时,写个0字节占位,如果配置为非空,则抛出异常
            if (data == null)
            {
                if (context.Config.NotNull) throw new InvalidOperationException("在非空设置下遇到空节点!" + context.Node.Path);
                writer.Write((Byte)0);
                return;
            }

            // 基础类型
            if (writer.WriteValue(data, encodeInt)) return;

            // 引用对象
            if (context.Config.UseRefObject)
            {
                // 对于非基本类型,先写入对象引用计数
                // 计数0表示是空对象
                if (context.Node.Depth > 1 && !context.Config.NotNull)
                {
                    Int32 n = context.Objects.IndexOf(data);
                    if (n >= 0)
                    {
                        // 该对象已经写入,这里写入引用计数即可
                        writer.WriteEncoded(n + 1);
                        return;
                    }
                }

                context.Objects.Add(data);
                // 不写对象引用计数
                if (context.Node.Depth > 1 && !context.Config.NotNull) writer.WriteEncoded(context.Objects.Count);
            }

            #region 数组、枚举、值类型、对象
            if (context.Type.IsArray)
            {
                WriteArray(context);
                return;
            }

            if (data is IEnumerable)
            {
                WriteEnumerable(context);
                return;
            }

            //else
            {
                if (context.Type == typeof(IPAddress))
                {
                    IPAddress ip = data as IPAddress;
                    Byte[] buffer = ip.GetAddressBytes();
                    if (!encodeInt)
                        writer.Write(buffer.Length);
                    else
                        writer.WriteEncoded(buffer.Length);
                    writer.Write(buffer);
                    return;
                }

                WriteObjectRef(context);
            }
            #endregion
        }
        /// <summary>
        /// 写入对象
        /// </summary>
        /// <remarks>
        /// 分为几种情况:
        /// 1,空引用直接写入0
        /// 2,基本值类型直接写入值
        /// 3,非基本值类型先查找是否已有引用,已有则写入引用计数(从1开始,因为0表示空引用),没有则添加到引用集合,不写引用计数
        /// 4,数组和枚举类型先写入元素个数,再依次写入元素
        /// 5,对象类型,反射得到属性和字段,一个个写入
        /// 值得注意的是,数据和枚举本也使用引用计数防止重复引用,同时包含引用计数和元素个数
        /// </remarks>
        /// <param name="context"></param>
        public void WriteMember(WriteContext context)
        {
            //WriteLog(context.Node.ToString());

            Stream stream = context.Writer.BaseStream;
            Int64 pos = stream.Position;
            if (OnSerializing(context))
            {
                WriteMemberInternal(context);
                OnSerialized(context);
            }
            Int64 pos2 = stream.Position;
            if (pos2 > pos)
            {
                stream.Seek(pos, SeekOrigin.Begin);
                Byte[] buffer = new Byte[pos2 - pos];
                stream.Read(buffer, 0, buffer.Length);

                WriteLog("{0} [{1}] {2}", context.Node.ToString(), buffer.Length, BitConverter.ToString(buffer).Replace("-", " "));
            }
        }
Exemple #9
0
 void IProtocolSerializable.OnSerialized(WriteContext context)
 {
 }
Exemple #10
0
 bool IProtocolSerializable.OnSerializing(WriteContext context)
 {
     return true;
 }
 /// <summary>
 /// 构造
 /// </summary>
 /// <param name="context"></param>
 public ProtocolSerializingEventArgs(WriteContext context)
 {
     Context = context;
 }