完全去除__MOBILE__,由std支持
大石头 authored at 2018-12-22 15:23:32
5.94 KiB
X
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Serialization;
using NewLife.Reflection;

namespace NewLife.Serialization
{
    /// <summary>Xml复合对象处理器</summary>
    public class XmlComposite : XmlHandlerBase
    {
        /// <summary>实例化</summary>
        public XmlComposite()
        {
            Priority = 100;
        }

        /// <summary>写入对象</summary>
        /// <param name="value">目标对象</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public override Boolean Write(Object value, Type type)
        {
            if (value == null) return false;

            // 不支持基本类型
            if (Type.GetTypeCode(type) != TypeCode.Object) return false;

            var ms = GetMembers(type);
            WriteLog("XmlWrite {0} 成员{1}个", type.Name, ms.Count);

            Host.Hosts.Push(value);

            //var xml = Host as Xml;
            //xml.WriteStart(type);
            try
            {
                // 获取成员
                foreach (var member in GetMembers(type))
                {
                    var mtype = GetMemberType(member);
                    Host.Member = member;

                    var name = SerialHelper.GetName(member);
                    var v = value.GetValue(member);
                    WriteLog("    {0}.{1} {2}", type.Name, member.Name, v);

                    if (!Host.Write(v, name, mtype)) return false;
                }
            }
            finally
            {
                //xml.WriteEnd();

                Host.Hosts.Pop();
            }

            return true;
        }

        /// <summary>尝试读取</summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public override Boolean TryRead(Type type, ref Object value)
        {
            if (type == null)
            {
                if (value == null) return false;
                type = value.GetType();
            }

            // 不支持基本类型
            if (Type.GetTypeCode(type) != TypeCode.Object) return false;
            // 不支持基类不是Object的特殊类型
            //if (type.BaseType != typeof(Object)) return false;
            if (!type.As<Object>()) return false;

            var reader = Host.GetReader();
            var xml = Host as Xml;

            // 判断类名是否一致
            var name = xml.CurrentName;
            if (!CheckName(name, type)) return false;

            var ms = GetMembers(type);
            WriteLog("XmlRead {0} 成员{1}个", type.Name, ms.Count);
            var dic = ms.ToDictionary(e => SerialHelper.GetName(e), e => e);

            if (value == null) value = type.CreateInstance();

            Host.Hosts.Push(value);

            try
            {
                if (reader.NodeType == XmlNodeType.Attribute)
                {
                    foreach (var item in dic)
                    {
                        var member = item.Value;
                        var v = reader.GetAttribute(item.Key);
                        WriteLog("    {0}.{1} {2}", type.Name, member.Name, v);

                        value.SetValue(member, v);
                    }
                }
                else
                {
                    // 获取成员
                    var member = ms[0];
                    while (reader.NodeType != XmlNodeType.None && reader.IsStartElement())
                    {
                        // 找到匹配的元素,否则跳过
                        if (!dic.TryGetValue(reader.Name, out member) || !member.CanWrite)
                        {
                            reader.Skip();
                            continue;
                        }

                        var mtype = GetMemberType(member);
                        Host.Member = member;

                        var v = value.GetValue(member);
                        WriteLog("    {0}.{1} {2}", type.Name, member.Name, v);

                        if (!Host.TryRead(mtype, ref v)) return false;

                        value.SetValue(member, v);
                    }
                }
            }
            finally
            {
                Host.Hosts.Pop();
            }

            return true;
        }

        #region 辅助
        private Boolean CheckName(String name, Type type)
        {
            if (type.Name.EqualIgnoreCase(name)) return true;

            // 当前正在序列化的成员
            var mb = Host.Member;
            if (mb != null)
            {
                var elm = mb.GetCustomAttribute<XmlElementAttribute>();
                if (elm != null) return elm.ElementName.EqualIgnoreCase(name);

                if (mb.Name.EqualIgnoreCase(name)) return true;
            }

            // 检查类型的Root
            var att = type.GetCustomAttribute<XmlRootAttribute>();
            if (att != null) return att.ElementName.EqualIgnoreCase(name);

            return false;
        }
        #endregion

        #region 获取成员
        /// <summary>获取成员</summary>
        /// <param name="type"></param>
        /// <returns></returns>
        protected virtual List<PropertyInfo> GetMembers(Type type) { return type.GetProperties(true).Cast<PropertyInfo>().ToList(); }

        static Type GetMemberType(MemberInfo member)
        {
            switch (member.MemberType)
            {
                case MemberTypes.Field:
                    return (member as FieldInfo).FieldType;
                case MemberTypes.Property:
                    return (member as PropertyInfo).PropertyType;
                default:
                    throw new NotSupportedException();
            }
        }
        #endregion
    }
}