反射库,类型增加As扩展,是否能够转为指定基类
大石头 authored at 2017-04-22 22:42:43
7.13 KiB
X
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;
using NewLife.Collections;
using NewLife.Reflection;

namespace NewLife.Serialization
{
    /// <summary>复合对象处理器</summary>
    public class JsonComposite : JsonHandlerBase
    {
        /// <summary>要忽略的成员</summary>
        public ICollection<String> IgnoreMembers { get; set; }

        /// <summary>实例化</summary>
        public JsonComposite()
        {
            Priority = 100;

            //IgnoreMembers = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
            IgnoreMembers = new HashSet<String>();
        }

        /// <summary>获取对象的Json字符串表示形式。</summary>
        /// <param name="value"></param>
        /// <returns>返回null表示不支持</returns>
        public override String GetString(Object value)
        {
            if (value == null) return String.Empty;

            var type = value.GetType();
            if (type == typeof(Guid)) return ((Guid)value).ToString();
            if (type == typeof(Byte[])) return Convert.ToBase64String((Byte[])value);
            if (type == typeof(Char[])) return new String((Char[])value);

            switch (Type.GetTypeCode(value.GetType()))
            {
                case TypeCode.Boolean:
                    return value + "";
                case TypeCode.Byte:
                case TypeCode.SByte:
                case TypeCode.Char:
                    return value + "";
                case TypeCode.DBNull:
                case TypeCode.Empty:
                    return String.Empty;
                case TypeCode.DateTime:
                    return value + "";
                case TypeCode.Decimal:
                    return value + "";
                case TypeCode.Single:
                case TypeCode.Double:
                    return value + "";
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                    return value + "";
                case TypeCode.String:
                    if (((String)value).IsNullOrEmpty()) return String.Empty;
                    return "\"{0}\"".F(value);
                case TypeCode.Object:
                default:
                    return null;
            }
        }

        /// <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("JsonWrite类{0} 共有成员{1}个", type.Name, ms.Count);

            Host.Hosts.Push(value);

            // 获取成员
            foreach (var member in ms)
            {
                if (IgnoreMembers != null && IgnoreMembers.Contains(member.Name)) continue;

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

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

                if (!Host.Write(v, mtype))
                {
                    Host.Hosts.Pop();
                    return false;
                }
            }
            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 ms = GetMembers(type);
            WriteLog("JsonRead类{0} 共有成员{1}个", type.Name, ms.Count);

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

            Host.Hosts.Push(value);

            // 成员序列化访问器
            var ac = value as IMemberAccessor;

            // 获取成员
            for (var i = 0; i < ms.Count; i++)
            {
                var member = ms[i];
                if (IgnoreMembers != null && IgnoreMembers.Contains(member.Name)) continue;

                var mtype = GetMemberType(member);
                Host.Member = member;
                WriteLog("    {0}.{1}", member.DeclaringType.Name, member.Name);

                // 成员访问器优先
                if (ac != null)
                {
                    // 访问器直接写入成员
                    if (ac.Read(Host, member))
                    {
                        // 访问器内部可能直接操作Hosts修改了父级对象,典型应用在于某些类需要根据某个字段值决定采用哪个派生类
                        var obj = Host.Hosts.Peek();
                        if (obj != value)
                        {
                            value = obj;
                            ms = GetMembers(value.GetType());
                            ac = value as IMemberAccessor;
                        }

                        continue;
                    }
                }

                Object v = null;
                if (!Host.TryRead(mtype, ref v))
                {
                    Host.Hosts.Pop();
                    return false;
                }

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

            return true;
        }

        #region 获取成员
        /// <summary>获取成员</summary>
        /// <param name="type"></param>
        /// <param name="baseFirst"></param>
        /// <returns></returns>
        protected virtual List<MemberInfo> GetMembers(Type type, Boolean baseFirst = true)
        {
            if (Host.UseProperty)
                return type.GetProperties(baseFirst).Cast<MemberInfo>().ToList();
            else
                return type.GetFields(baseFirst).Cast<MemberInfo>().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
    }
}