修正因EndOfStream而导致的Json反序列化错误
nnhy 编写于 2012-05-14 17:10:08
X
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using System.Text;
using NewLife.Reflection;

namespace NewLife.Serialization
{
    /// <summary>Json读取器</summary>
    public class JsonReader : TextReaderBase<JsonSettings>
    {
        #region 属性
        long line = 1, column = 1;

        private TextReader _Reader;
        /// <summary>读取器</summary>
        public TextReader Reader
        {
            get { return _Reader ?? (_Reader = new StreamReader(Stream, Settings.Encoding)); }
            set
            {
                _Reader = value;

                StreamReader sr = _Reader as StreamReader;
                if (sr != null)
                {
                    if (Settings.Encoding != sr.CurrentEncoding) Settings.Encoding = sr.CurrentEncoding;
                    if (Stream != sr.BaseStream) Stream = sr.BaseStream;
                }
            }
        }

        /// <summary>数据流。更改数据流后,重置Reader为空,以使用新的数据流</summary>
        public override Stream Stream
        {
            get { return base.Stream; }
            set
            {
                if (base.Stream != value) _Reader = null;
                base.Stream = value;
            }
        }

        /// <summary>获取一个值,该值表示当前的流位置是否在流的末尾。</summary>
        /// <returns>如果当前的流位置在流的末尾,则为 true;否则为 false。</returns>
        public override bool EndOfStream
        {
            get
            {
                var r = Reader as StreamReader;
                if (r != null) return r.EndOfStream;

                var s = Stream;
                if (s != null) return s.Position == s.Length;

                return false;
            }
        }
        #endregion

        #region 构造方法
        /// <summary>构造方法</summary>
        public JsonReader()
            : base()
        {
            Settings.DepthLimit = 1000;
#if DEBUG
            Settings.DepthLimit = 10;
#endif
        }
        #endregion

        #region 基础元数据
        #region 字节/字节数组
        /// <summary>读取字节</summary>
        /// <returns></returns>
        public override byte ReadByte()
        {
            string str;
            byte ret;
            AssertReadNextAtomElement("期望是0-255的数字", out str, AtomElementType.NUMBER);
            if (!Byte.TryParse(str, out ret))
            {
                throw new JsonReaderAssertException(line, column, new AtomElementType[] { AtomElementType.NUMBER }, AtomElementType.NUMBER, "期望是0-255的数字,而实际是:" + str);
            }
            return ret;
        }

        /// <summary>读取字节数组</summary>
        /// <param name="count"></param>
        /// <returns></returns>
        public override byte[] ReadBytes(int count)
        {
            byte[] ret = null;
            if (!ReadEnumerable<byte>(ref ret)) return new byte[] { };

            return ret;
        }
        #endregion

        #region 布尔
        /// <summary>从当前流位置读取一个布尔型数据</summary>
        /// <returns></returns>
        public override bool ReadBoolean()
        {
            switch (AssertReadNextAtomElement("期望是true或者false", AtomElementType.TRUE, AtomElementType.FALSE))
            {
                case AtomElementType.TRUE:
                    return true;
                case AtomElementType.FALSE:
                default:
                    return false;
            }
        }
        #endregion

        #region 时间
        /// <summary>从当前流位置读取一个日期时间型数据,支持的格式参考ParseDateTimeString的说明</summary>
        /// <returns></returns>
        public override DateTime ReadDateTime()
        {
            string str;
            AtomElementType atype = AssertReadNextAtomElement("期望是包含日期时间内容的字符串", out str, AtomElementType.LITERAL, AtomElementType.STRING);
            DateTime dt;
            if (!TryParseDateTimeString(str, out dt))
            {
                throw new JsonReaderAssertException(line, column, new AtomElementType[] { AtomElementType.LITERAL, AtomElementType.STRING }, atype, "期望是日期时间格式的内容,实际是" + str);
            }
            return dt;
        }

        static string[] DateTimeParseFormats = { "yyyy-MM-ddTHH:mm:ss.fffZ", //包含毫秒部分的ISO8601格式
                                                   "yyyy-MM-ddTHH:mm:ssZ", //不包含毫秒部分的ISO8601格式,和json2.js的toJSON()格式相同(ff3.5 ie8已原生实现Date.toJSON())
                                                   "ddd, dd MMM yyyy HH:mm:ss GMT", //js中toGMTString()返回的格式
                                                   "yyyy-MM-dd HH:mm:ss", //一般是测试用途的手写格式,不建议使用,下同
                                                   "yyyy-MM-dd"
                                               };

        static DateTime BaseDateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

        /// <summary>解析日期时间字符串,可以处理多种日期时间格式,包括JsDateTimeFormats枚举中的格式,以及js中toGMTString()的格式</summary>
        /// <param name="str"></param>
        /// <param name="ret"></param>
        /// <returns></returns>
        public static bool TryParseDateTimeString(string str, out DateTime ret)
        {
            if (str.Length > 10 && str.Length < 26 && str.Substring(0, 7) == @"\/Date(")
            // 处理System.Web.Script.Serialization.JavaScriptSerializer日期时间格式,类似 \/Date(12345678)\/
            // 因为MinDateTime和MaxDateTime的十进制毫秒数是15位长度的字符串,最少是1位长度字符串,所以预期长度是11位到25位
            {
                string[] s = str.Split('(', ')');
                long ms;
                if (s.Length >= 3 && s[2] == @"\/" && long.TryParse(s[1], out ms))
                {
                    ret = BaseDateTime.AddMilliseconds(ms);
                    return true;
                }
            }
            if (DateTime.TryParseExact(str, DateTimeParseFormats, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out ret))
            {
                return true;
            }
            long ticks;
            if (long.TryParse(str, out ticks)) //dotnet中的Ticks,不建议
            {
                ret = new DateTime(ticks);
                return true;
            }
            return false;
        }
        #endregion

        #region 数字
        /// <summary>数字类型 包括整型和浮点型</summary>
        public static readonly AtomElementType[] NUMBER_TYPES = { AtomElementType.NUMBER, AtomElementType.NUMBER_EXP,
                                                                    AtomElementType.FLOAT, AtomElementType.FLOAT_EXP };
        /// <summary>整型类型</summary>
        public static readonly AtomElementType[] INTEGER_TYPES = { AtomElementType.NUMBER, AtomElementType.NUMBER_EXP };

        /// <summary>从当前流位置读取一个指定T类型的数字,T应该是int long float double及相关类型</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="exceptMsg">断言读取时断言失败的附加异常信息</param>
        /// <param name="expected">期望的节点类型,和T参数有关,一般浮点数额外有AtomElementType.FLOAT</param>
        /// <returns></returns>
        T ReadNumber<T>(string exceptMsg, params AtomElementType[] expected) where T : IConvertible
        {
            string str;
            AtomElementType actual = AssertReadNextAtomElement(exceptMsg, out str, expected);
            NumberStyles numStyles = GetExponentOrNotStyle(str, expected, actual);

            IConvertible ret;
            if (ReadNumber<T>(str, numStyles, out ret))
            {
                return (T)ret;
            }
            throw new JsonReaderAssertException(line, column, expected, actual, string.Format("字符串{0} 不是有效的数字类型:{1}", str, typeof(T).FullName));
        }

        /// <summary>从指定字符串中尝试读取指定T类型的数字,T应该是int long float double及相关类型</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="str"></param>
        /// <param name="numStyles"></param>
        /// <param name="result">返回值,可以直接强类型转换或者使用ToXXX转换</param>
        /// <returns></returns>
        bool ReadNumber<T>(string str, NumberStyles numStyles, out IConvertible result) where T : IConvertible
        {
            bool ret;
            switch (Type.GetTypeCode(typeof(T)))
            {
                case TypeCode.Byte:
                    byte b;
                    ret = Byte.TryParse(str, numStyles, CultureInfo.InvariantCulture, out b);
                    result = b;
                    return ret;
                case TypeCode.Decimal:
                    decimal dec;
                    ret = Decimal.TryParse(str, numStyles, CultureInfo.InvariantCulture, out dec);
                    result = dec;
                    return ret;
                case TypeCode.Double:
                    double d;
                    ret = Double.TryParse(str, numStyles, CultureInfo.InvariantCulture, out d);
                    result = d;
                    return ret;
                case TypeCode.Int16:
                    short s;
                    ret = Int16.TryParse(str, numStyles, CultureInfo.InvariantCulture, out s);
                    result = s;
                    return ret;
                case TypeCode.Int32:
                    int i;
                    ret = Int32.TryParse(str, numStyles, CultureInfo.InvariantCulture, out i);
                    result = i;
                    return ret;
                case TypeCode.Int64:
                    long l;
                    ret = Int64.TryParse(str, numStyles, CultureInfo.InvariantCulture, out l);
                    result = l;
                    return ret;
                case TypeCode.SByte:
                    sbyte sb;
                    ret = SByte.TryParse(str, numStyles, CultureInfo.InvariantCulture, out sb);
                    result = sb;
                    return ret;
                case TypeCode.Single:
                    float f;
                    ret = Single.TryParse(str, numStyles, CultureInfo.InvariantCulture, out f);
                    result = f;
                    return ret;
                case TypeCode.UInt16:
                    UInt16 us;
                    ret = UInt16.TryParse(str, numStyles, CultureInfo.InvariantCulture, out us);
                    result = us;
                    return ret;
                case TypeCode.UInt32:
                    UInt32 ui;
                    ret = UInt32.TryParse(str, numStyles, CultureInfo.InvariantCulture, out ui);
                    result = ui;
                    return ret;
                case TypeCode.UInt64:
                    UInt64 ul;
                    ret = UInt64.TryParse(str, numStyles, CultureInfo.InvariantCulture, out ul);
                    result = ul;
                    return ret;
                default:
                    result = default(T);
                    return false;
            }
        }

        /// <summary>从给定的实际原子节点类型中返回对应的数字格式</summary>
        /// <param name="str"></param>
        /// <param name="expected"></param>
        /// <param name="actual">实际原子节点类型</param>
        /// <returns></returns>
        NumberStyles GetExponentOrNotStyle(string str, AtomElementType[] expected, AtomElementType actual)
        {
            return NumberStyles.AllowLeadingSign |
                NumberStyles.AllowDecimalPoint |
                (actual == AtomElementType.NUMBER_EXP || actual == AtomElementType.FLOAT_EXP ? NumberStyles.AllowExponent : NumberStyles.None);
        }

        static readonly string Int16AssertMsg = string.Format("期望是在{0}和{1}之间的数字", Int16.MinValue, Int16.MaxValue);
        /// <summary>从当前流位置读取一个16位长度的整型数字</summary>
        /// <returns></returns>
        public override short ReadInt16() { return ReadNumber<short>(Int16AssertMsg, INTEGER_TYPES); }

        static readonly string Int32AssertMsg = string.Format("期望是在{0}和{1}之间的数字", Int32.MinValue, Int32.MaxValue);
        /// <summary>从当前流位置读取一个32位长度的整型数字</summary>
        /// <returns></returns>
        public override int ReadInt32() { return ReadNumber<int>(Int32AssertMsg, INTEGER_TYPES); }

        static readonly string Int64AssertMsg = string.Format("期望是在{0}和{1}之间的数字", Int64.MinValue, Int64.MaxValue);
        /// <summary>从当前流位置读取一个64位长度的整型数字</summary>
        /// <returns></returns>
        public override long ReadInt64() { return ReadNumber<long>(Int64AssertMsg, INTEGER_TYPES); }

        static readonly string SingleAssertMsg = string.Format("期望是在{0}和{1}之间的单精度浮点数", Single.MinValue, Single.MaxValue);
        /// <summary>从当前流位置读取一个单精度浮点数</summary>
        /// <returns></returns>
        public override float ReadSingle() { return ReadNumber<float>(SingleAssertMsg, NUMBER_TYPES); }

        static readonly string DoubleAssertMsg = string.Format("期望是在{0}和{1}之间的双精度浮点数", Double.MinValue, Double.MaxValue);
        /// <summary>从当前流位置读取一个双精度浮点数</summary>
        /// <returns></returns>
        public override double ReadDouble() { return ReadNumber<double>(DoubleAssertMsg, NUMBER_TYPES); }

        static readonly string DecimalAssertMsg = string.Format("期望是在{0}的{1}之间的十进制数", Decimal.MinValue, Decimal.MaxValue);
        /// <summary>从当前流位置读取一个十进制数</summary>
        /// <returns></returns>
        public override decimal ReadDecimal() { return ReadNumber<decimal>(DecimalAssertMsg, NUMBER_TYPES); }
        #endregion

        #region 字符串
        /// <summary>从当前流位置读取一个字符串</summary>
        /// <returns></returns>
        public override string ReadString()
        {
            string ret;
            if (AtomElementType.NULL == AssertReadNextAtomElement("期望字符串值或null", out ret, AtomElementType.STRING, AtomElementType.NULL))
            {
                return null;
            }
            return ret;
        }

        /// <summary>从当前流位置读取一个字符,如果读到的是字符串,将取第一个字符;如果读到的是数字,将作为Unicode字符处理;或者读到null</summary>
        /// <returns></returns>
        public override char ReadChar()
        {
            string str;
            AtomElementType t = AssertReadNextAtomElement("期望字符字符串或数字,将转换成字符", out str, AtomElementType.NULL, AtomElementType.STRING, AtomElementType.NUMBER);
            switch (t)
            {
                case AtomElementType.NULL:
                case AtomElementType.STRING:
                    if (str != null && str.Length > 0)
                    {
                        return str[0];
                    }
                    else
                    {
                        return '\0';
                    }
                case AtomElementType.NUMBER:
                default:
                    int n;
                    if (Int32.TryParse(str, out n))
                    {
                        return (char)n;
                    }
                    else
                    {
                        throw new JsonReaderAssertException(line, column, new AtomElementType[] { AtomElementType.STRING, AtomElementType.NUMBER }, t, "期望的字符Unicode代码超出预期,实际是:" + str);
                    }

            }
        }

        /// <summary>从当前流位置读取字符数组</summary>
        /// <param name="count"></param>
        /// <returns></returns>
        public override char[] ReadChars(int count)
        {
            string str;
            AtomElementType atype = AssertReadNextAtomElement(true, "期望是字符数组,字符串或者null", out str, AtomElementType.BRACKET_OPEN, AtomElementType.STRING, AtomElementType.LITERAL);
            if (atype == AtomElementType.STRING)
            {
                AssertReadNextAtomElement("期望是字符串", out str, AtomElementType.STRING);
                return str.ToCharArray();
            }
            else if (atype == AtomElementType.LITERAL)
            {
                AssertReadNextAtomElement("期望是null", out str, AtomElementType.NULL);
                return new char[] { };
            }
            else
            {
                char[] ret = null;
                if (!ReadEnumerable(ref ret))
                {
                    return new char[] { };
                }
                return ret;
            }
        }
        #endregion
        #endregion

        #region 扩展类型
        /// <summary>读取Guid</summary>
        /// <returns></returns>
        protected override Guid OnReadGuid()
        {
            try
            {
                return base.OnReadGuid();
            }
            catch (Exception ex)
            {
                throw new JsonReaderAssertException(line, column, new AtomElementType[] { AtomElementType.STRING }, AtomElementType.STRING, "不是有效的Guid格式" + ex.Message);
            }
        }

        /// <summary>读取IP地址</summary>
        /// <returns></returns>
        protected override IPAddress OnReadIPAddress()
        {
            try
            {
                return base.OnReadIPAddress();
            }
            catch (Exception ex)
            {
                throw new JsonReaderAssertException(line, column, new AtomElementType[] { AtomElementType.STRING }, AtomElementType.STRING, "不是有效的IP地址" + ex.Message);
            }
        }

        /// <summary>读取IP端口地址</summary>
        /// <returns></returns>
        protected override IPEndPoint OnReadIPEndPoint()
        {
            try
            {
                return base.OnReadIPEndPoint();
            }
            catch (Exception ex)
            {
                throw new JsonReaderAssertException(line, column, new AtomElementType[] { AtomElementType.STRING }, AtomElementType.STRING, "不是有效的IP端口地址" + ex.Message);
            }
        }
        #endregion

        #region 枚举类型
        /// <summary></summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool ReadEnumerable<T>(ref T[] value)
        {
            object lst = null;
            if (!ReadEnumerable(typeof(T[]), ref lst)) return false;
            if (lst == null) return false;
            if (!(lst is T[])) return false;
            value = (T[])lst;
            return true;
        }

        /// <summary>从当前流位置读取一个枚举类型</summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public override bool ReadEnumerable(Type type, ref object value, ReadObjectCallback callback)
        {
            AtomElementType atype = AssertReadNextAtomElement("期望是数组声明开始符号[或null", AtomElementType.BRACKET_OPEN, AtomElementType.NULL);
            if (atype == AtomElementType.NULL)
            {
                value = null;
                return true;
            }
            int d = ComplexObjectDepth++;
            bool ret = ComplexObjectDepthIsOverflow() || base.ReadEnumerable(type, ref value, callback);
            int n = ComplexObjectDepth - d;
            if (n > 0)
            {
                SkipNext(n);
            }
            else if (n < 0)
            {
                throw new JsonReaderAssertException(line, column, new AtomElementType[] { AtomElementType.BRACE_CLOSE }, AtomElementType.NONE, "数组解析异常,读取了过多的数组结束符:]");
            }
            return ret;
        }

        /// <summary>从当前流位置读取枚举项目</summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <param name="index"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        protected override bool OnReadItem(Type type, ref object value, int index, ReadObjectCallback callback)
        {
            string str;
            AtomElementType atype = AssertReadNextAtomElement(true, "期望是枚举项目,可以是枚举结束符(]),分隔符逗号,或具体的数组项", out str,
                AtomElementType.STRING, AtomElementType.TRUE, AtomElementType.FALSE, AtomElementType.NULL,
                AtomElementType.NUMBER, AtomElementType.NUMBER_EXP, AtomElementType.FLOAT, AtomElementType.FLOAT_EXP,
                AtomElementType.COMMA, AtomElementType.BRACE_OPEN, AtomElementType.BRACKET_OPEN,
                AtomElementType.BRACKET_CLOSE, AtomElementType.LITERAL);
            if (atype == AtomElementType.BRACKET_CLOSE)
            {
                AssertReadNextAtomElement("期望是枚举结束符号(])", AtomElementType.BRACKET_CLOSE);
                ComplexObjectDepth--;
                return false;
            }
            else if (atype == AtomElementType.COMMA)
            {
                AssertReadNextAtomElement("期望是枚举项目分割符", AtomElementType.COMMA);
            }

            WriteLog("ReadEnumerableItem", type != null ? type.Name : "Not found item type", index);
            //if (!IsExactType(type)) //注释是因为ReadObject方法中已经没有ReadType的调用,最终将由OnReadObject方法处理
            //{
            //    type = typeof(ReservedTypeClass);
            //}
            if (!ReadObject(type, ref value, callback)) return false;

            return true;
        }
        #endregion

        #region 序列化接口
        /// <summary>读取实现了序列化接口的类型</summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public override bool ReadSerializable(Type type, ref object value, ReadObjectCallback callback)
        {
            if (!typeof(ISerializable).IsAssignableFrom(type)) return false;

            AtomElementType atype = AssertReadNextAtomElement("期望实现了序列化接口的对象开始符号或null", AtomElementType.BRACE_OPEN, AtomElementType.NULL);
            if (atype == AtomElementType.NULL)
            {
                value = null;
                return true;
            }
            int d = ComplexObjectDepth++;
            bool ret = ComplexObjectDepthIsOverflow();
            if (ret) // 即使达到了读取深度限制,并且对象尚未创建,也创建类实例,以避免产生null
            {
                if (value == null)
                {
                    value = TypeX.CreateInstance(type);
                }
            }
            else
            {
                ret = base.ReadSerializable(type, ref value, callback);
            }
            int n = ComplexObjectDepth - d;
            if (n > 0) //尚未读到当前对象的结束符}
            {
                SkipNext(n);
            }
            else if (n < 0)
            {
                throw new JsonReaderAssertException(line, column, new AtomElementType[] { AtomElementType.BRACKET_CLOSE }, AtomElementType.NONE, "实现了序列化接口的对象解析异常,读取了过多的对象结束符:}");
            }
            return ret;
        }
        #endregion

        #region 字典
        /// <summary>从当前流位置读取一个字典类型</summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public override bool ReadDictionary(Type type, ref object value, ReadObjectCallback callback)
        {
            AtomElementType atype = AssertReadNextAtomElement("期望字典开始符号{或null", AtomElementType.BRACE_OPEN, AtomElementType.NULL);
            if (atype == AtomElementType.NULL)
            {
                value = null;
                return true;
            }
            int d = ComplexObjectDepth++;
            bool ret = ComplexObjectDepthIsOverflow() || base.ReadDictionary(type, ref value, callback);

            int n = ComplexObjectDepth - d;
            if (n > 0)
            {
                SkipNext(n);
            }
            else if (n < 0)
            {
                throw new JsonReaderAssertException(line, column, new AtomElementType[] { AtomElementType.BRACE_CLOSE }, AtomElementType.NONE, "字典解析异常,读取了过多的字典结束符:}");
            }
            return ret;
        }

        /// <summary>从当前流位置读取一个字典项</summary>
        /// <param name="keyType"></param>
        /// <param name="valueType"></param>
        /// <param name="value"></param>
        /// <param name="index"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        protected override bool OnReadDictionaryEntry(Type keyType, Type valueType, ref System.Collections.DictionaryEntry value, int index, ReadObjectCallback callback)
        {
            string str;
            AtomElementType atype = AssertReadNextAtomElement("期望字典项分隔符(逗号)或字典结束或字典项名称", out str, AtomElementType.COMMA, AtomElementType.BRACE_CLOSE, AtomElementType.STRING);

            if (atype == AtomElementType.COMMA)
            {
                atype = AssertReadNextAtomElement("期望字典项名称", out str, AtomElementType.STRING);
            }
            else if (atype == AtomElementType.BRACE_CLOSE)
            {
                ComplexObjectDepth--;
                return false;
            }

            AssertReadNextAtomElement("期望字典项名称值分割符(冒号)", AtomElementType.COLON);

            WriteLog("ReadDictionaryEntry", str, valueType != null ? valueType.Name : "Not found value type", index);

            //if (!IsExactType(valueType)) //注释是因为ReadObject方法中已经没有ReadType的调用,将最终由OnReadObject方法处理
            //{
            //    valueType = typeof(ReservedTypeClass);
            //}
            object entryValue = null;
            if (!ReadObject(valueType, ref entryValue, callback)) return false;

            value.Key = str; // json的key必须是字符串
            value.Value = entryValue;
            return true;
        }
        #endregion

        #region 读取json的原子操作
        /// <summary>
        /// 断言读取下一个原子元素,返回实际读到的原子元素类型,一般用于断言{}[]:,
        /// 
        /// 要得到具体读取到的值应使用另外一个重载
        /// </summary>
        /// <param name="msg">断言失败时的附加异常信息</param>
        /// <param name="expected">期望的原子元素类型</param>
        /// <exception cref="JsonReaderAssertException">如果断言失败</exception>
        /// <returns></returns>
        AtomElementType AssertReadNextAtomElement(string msg, params AtomElementType[] expected)
        {
            string s;
            return AssertReadNextAtomElement(msg, out s, expected);
        }

        /// <summary>
        /// 断言读取下一个原子元素,返回实际读到的原子元素类型
        /// 
        /// </summary>
        /// <param name="msg">断言失败时的附加异常信息</param>
        /// <param name="str">实际读到的内容,字面值是直接的字符串,字符串类型也是实际的字符串(不包括字符串头尾的双引号)</param>
        /// <param name="expected">期望的原子元素类型</param>
        /// <exception cref="JsonReaderAssertException">如果断言失败</exception>
        /// <returns></returns>
        AtomElementType AssertReadNextAtomElement(string msg, out string str, params AtomElementType[] expected)
        {
            return AssertReadNextAtomElement(false, msg, out str, expected);
        }

        /// <summary>
        /// 断言读取下一个原子元素,返回实际读到的原子元素类型
        /// 
        /// 可以选择是否仅仅Peek而不移动流位置
        /// </summary>
        /// <param name="onlyPeek">是否仅Peek而不移动流位置(不移动到有效值的位置),这将会使str不会返回字符串内容(仅一个双引号)</param>
        /// <param name="msg"></param>
        /// <param name="str"></param>
        /// <param name="expected"></param>
        /// <returns></returns>
        AtomElementType AssertReadNextAtomElement(bool onlyPeek, string msg, out string str, params AtomElementType[] expected)
        {
            AtomElementType t = ReadNextAtomElement(onlyPeek, out str);
            if (Array.IndexOf(expected, t) == -1)
            {
                long col = column;
                if (onlyPeek)
                {
                    col += str != null && str.Length > 0 ? str.Length : 1;
                }
                throw new JsonReaderAssertException(line, col, expected, t, msg);
            }
            return t;
        }

        /// <summary>读取下一个原子元素,非{} []这类复合元素</summary>
        /// <param name="str"></param>
        /// <returns></returns>
        AtomElementType ReadNextAtomElement(out string str) { return ReadNextAtomElement(false, out str); }

        /// <summary>读取下一个原子元素,非{} []这类复合元素</summary>
        /// <param name="str"></param>
        /// <param name="onlyPeek">是否仅Peek而不移动流位置(不移动到有效值的位置),这将会使str不会返回字符串内容(仅一个双引号)</param>
        /// <returns></returns>
        AtomElementType ReadNextAtomElement(bool onlyPeek, out string str)
        {
            str = null;
            while (true)
            {
                int c = Reader.Peek();
                switch (c)
                {
                    case -1:
                        if (!onlyPeek) MoveNextStreamPostition();
                        return AtomElementType.NONE;
                    case ' ':
                    case '\t':
                        MoveNextStreamPostition();
                        continue;
                    case '\r':
                    case '\n':
                        MoveNextStreamPostition();
                        if (c == '\r' && Reader.Peek() == '\n')
                        {
                            MoveNextStreamPostition();
                        }
                        column = 1;
                        line++;
                        continue;
                    case '{':
                        if (!onlyPeek) MoveNextStreamPostition();
                        return AtomElementType.BRACE_OPEN;
                    case '}':
                        if (!onlyPeek) MoveNextStreamPostition();
                        return AtomElementType.BRACE_CLOSE;
                    case '[':
                        if (!onlyPeek) MoveNextStreamPostition();
                        return AtomElementType.BRACKET_OPEN;
                    case ']':
                        if (!onlyPeek) MoveNextStreamPostition();
                        return AtomElementType.BRACKET_CLOSE;
                    case ':':
                        if (!onlyPeek) MoveNextStreamPostition();
                        return AtomElementType.COLON;
                    case ',':
                        if (!onlyPeek) MoveNextStreamPostition();
                        return AtomElementType.COMMA;
                    case '"':
                        if (!onlyPeek) MoveNextStreamPostition();
                        else
                        {
                            str = "\"";
                            return AtomElementType.STRING;
                        }
                        AtomElementType sret = ReadNextString(out str);
                        return sret;
                    default:
                        AtomElementType lret = ReadNextLiteral(onlyPeek, out str);
                        return lret;
                }
            }
        }

        /// <summary>将当前输入流位置向后移动一个字符,并返回读取到的字符</summary>
        /// <returns></returns>
        int MoveNextStreamPostition()
        {
            column++;
            return Reader.Read();
        }

        /// <summary>读取下一个字符串,当前reader流已经在"之后,读取到的字符串应该是不包含结尾的双引号</summary>
        /// <param name="str"></param>
        /// <returns></returns>
        AtomElementType ReadNextString(out string str)
        {
            StringBuilder sb = new StringBuilder();
            bool isContinue = true;
            int c = 0;
            while (isContinue)
            {
                c = Reader.Peek();
                switch (c)
                {
                    case '"':
                        MoveNextStreamPostition();
                        isContinue = false;
                        break;
                    case '\\':
                        MoveNextStreamPostition();
                        sb.Append(ReadNextEscapeChar());
                        break;
                    case '\b':
                        MoveNextStreamPostition();
                        sb.Append('\b');
                        break;
                    case '\f':
                        MoveNextStreamPostition();
                        sb.Append('\f');
                        break;
                    case '\t':
                        MoveNextStreamPostition();
                        column += 3; // 制表符宽度4列
                        sb.Append('\t');
                        break;
                    default:
                        if (c < 32)
                        {
                            throw new JsonReaderParseException(line, column, "字符串未正确的结束");
                        }
                        MoveNextStreamPostition();
                        sb.Append((char)c);
                        if (c > 2042) column++; //宽字符
                        break;
                }
            }
            str = sb.ToString();
            return AtomElementType.STRING;
        }

        /// <summary>读取下一个转义字符,流已处于转义符\后</summary>
        /// <returns></returns>
        string ReadNextEscapeChar()
        {
            int c = MoveNextStreamPostition();
            switch (c)
            {
                case 'b':
                    return "\b";
                case 'f':
                    return "\f";
                case 'n':
                    return "\n";
                case 'r':
                    return "\r";
                case 't':
                    return "\t";
                case 'u':
                    char[] unicodeChar = new char[4];
                    int n = Reader.ReadBlock(unicodeChar, 0, 4);
                    if (n != 4)
                    {
                        throw new JsonReaderParseException(line, column, "Unicode转义字符长度应该是4");
                    }
                    column += 4;
                    string str = new string(unicodeChar);
                    UInt16 charCode;
                    if (UInt16.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out charCode))
                    {
                        return "" + (char)charCode;
                    }
                    return "u" + str;//无法识别的将作为原始字符串输出
                default:
                    if (c > 2042) column++; //宽字符
                    return "" + (char)c;
            }
        }

        /// <summary>读取下一个字面值,可能是true false null 数字 无法识别,调用时第一个字符一定是一个字面值</summary>
        /// <param name="onlyPeek">是否仅Peek而不移动流位置(不移动到有效值的位置),这将会使str不会返回字符串内容(仅一个双引号)</param>
        /// <param name="str"></param>
        /// <returns></returns>
        AtomElementType ReadNextLiteral(bool onlyPeek, out string str)
        {
            StringBuilder sb = new StringBuilder();
            bool isContinue = true;
            int c = 0;
            bool hasDigit = false, hasLiteral = false, hasDot = false, hasExp = false;
            int lastChar = -1;
            while (isContinue)
            {
                c = Reader.Peek();
                switch (c)
                {
                    case '-':
                    case '+':
                        // json.org中规定-能在第一位和e符号后出现,而+仅仅只能在e符号后出现,这里忽略了这样的差异,允许+出现在第一位
                        if (!onlyPeek) MoveNextStreamPostition();
                        sb.Append((char)c);
                        if (sb.Length == 1 || //第一个字符
                            (sb.Length > 2 && hasDigit && !hasLiteral && hasExp && (lastChar == 'e' || lastChar == 'E')) //科学计数法e符号后
                            )
                        {
                            hasDigit = true; //作为数字
                        }
                        else
                        {
                            hasLiteral = true;
                        }
                        break;
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9': //数字
                        if (!onlyPeek) MoveNextStreamPostition();
                        sb.Append((char)c);
                        hasDigit = true;
                        break;
                    case '.': //浮点数
                        if (!onlyPeek) MoveNextStreamPostition();
                        sb.Append((char)c);
                        if (!hasDot) //仅出现一次的.符号
                        {
                            hasDot = true;
                        }
                        else
                        {
                            hasLiteral = true;
                        }
                        break;
                    case 'e':
                    case 'E': //科学计数法的e符号
                        if (!onlyPeek) MoveNextStreamPostition();
                        sb.Append((char)c);
                        if (!hasExp) //仅出现一次的e符号
                        {
                            hasExp = true;
                        }
                        else
                        {
                            hasLiteral = true;
                        }
                        break;
                    default:
                        if (c < 32 || " \t,{}[]:".IndexOf((char)c) != -1) //结束符号
                        {
                            isContinue = false;
                        }
                        else //其它符号
                        {
                            if (!onlyPeek)
                            {
                                if (c > 2042) column++; //宽字符
                                MoveNextStreamPostition();
                            }
                            sb.Append((char)c);
                            hasLiteral = true;
                        }
                        break;
                }
                lastChar = c;
                if (onlyPeek) break;
            }
            str = sb.ToString();

            if (hasDigit && !hasDot && !hasLiteral || onlyPeek && hasDigit)
            {
                return hasExp ? AtomElementType.NUMBER_EXP : AtomElementType.NUMBER;
            }
            else if (hasDigit && hasDot && !hasLiteral || onlyPeek && hasDot)
            {
                return hasExp ? AtomElementType.FLOAT_EXP : AtomElementType.FLOAT;
            }
            else
            {
                if (!hasDigit && str.ToLower() == "true" || onlyPeek && str.ToLower() == "t")
                {
                    return AtomElementType.TRUE;
                }
                else if (!hasDigit && str.ToLower() == "false" || onlyPeek && str.ToLower() == "f")
                {
                    return AtomElementType.FALSE;
                }
                else if (!hasDigit && str.ToLower() == "null" || onlyPeek && str.ToLower() == "n")
                {
                    return AtomElementType.NULL;
                }
                else
                {
                    return AtomElementType.LITERAL;
                }
            }
        }

        /// <summary>跳过下一个值,可以是跳过对象声明(以及对象成员名称 成员值声明),数组声明,以及基础类型</summary>
        void SkipNext() { SkipNext(0); }

        /// <summary>跳过下面的值,并指定初始复合对象深度,通过提供大于0的初始深度可以跳过一直到 偏移指定深度 的复合对象位置,一般是读取到]或者}符号之后</summary>
        /// <param name="initDepth">初始化复合对象深度,应该是大于等于0的数字,小于0时将不做任何操作</param>
        void SkipNext(int initDepth)
        {
            if (initDepth < 0) return;
            int skipDepth = initDepth;
            string s;
            do
            {
                switch (ReadNextAtomElement(out s))
                {
                    case AtomElementType.NONE:
                        skipDepth = 0;//直接跳出
                        break;
                    case AtomElementType.BRACE_OPEN:
                        skipDepth++;
                        break;
                    case AtomElementType.BRACE_CLOSE:
                        skipDepth--;
                        break;
                    case AtomElementType.BRACKET_OPEN:
                        skipDepth++;
                        break;
                    case AtomElementType.BRACKET_CLOSE:
                        skipDepth--;
                        break;
                    default:
                        break;
                }
            } while (skipDepth > 0);
            ComplexObjectDepth -= initDepth;
        }
        #endregion

        #region 读取对象
        /// <summary>复合对象深度,包括自定义对象和字典,主要用于平衡[]{},用于成员数量不一致时</summary>
        int ComplexObjectDepth = 0;
        /// <summary>自动探测类型时断言的原子元素类型</summary>
        static AtomElementType[] AUTODETECT_TYPES = {
                                                 AtomElementType.BRACE_OPEN, AtomElementType.BRACKET_OPEN,
                                                 AtomElementType.STRING,
                                                 AtomElementType.NUMBER, AtomElementType.FLOAT,
                                                 AtomElementType.TRUE, AtomElementType.FALSE,
                                                 AtomElementType.NULL, AtomElementType.LITERAL 
                                             };
        /// <summary>尝试读取成员时期望的原子元素类型</summary>
        static AtomElementType[] MEMBERNAME_EXPECTED_TYPES = { AtomElementType.COMMA, AtomElementType.STRING, AtomElementType.BRACE_CLOSE };
        /// <summary>从当前流位置读取一个对象</summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        protected override bool OnReadObject(Type type, ref object value, ReadObjectCallback callback)
        {
            if (type == typeof(ReservedTypeClass) || !IsExactType(type))
            {
                //探测类型 true,false,null,number,float这些返回类型不是可靠的
                string str;
                AtomElementType atype = AssertReadNextAtomElement(true, "期望是自动探测可接受的类型,包括对象,字符串,数字,{,[.无法解析的将会跳过", out str, AUTODETECT_TYPES);
                switch (atype)
                {
                    case AtomElementType.BRACE_OPEN:
                        type = typeof(ReservedTypeClass);
                        break;
                    case AtomElementType.BRACKET_OPEN:
                        type = typeof(ReservedTypeClass[]);
                        break;
                    case AtomElementType.STRING:
                        str = ReadString();
                        DateTime dt;
                        if (TryParseDateTimeString(str, out dt)) //这里是硬编码,探测日期时间类型
                        {
                            value = dt;
                            return true;
                        }
                        else
                        {
                            value = str;
                            return true;
                        }
                    case AtomElementType.TRUE:
                    case AtomElementType.FALSE:
                        try
                        {
                            value = ReadBoolean();
                            return true;
                        }
                        catch (JsonReaderParseException)
                        {
                            goto default;
                        }
                    case AtomElementType.NULL:
                        try
                        {
                            AssertReadNextAtomElement("期望是null", AtomElementType.NULL);
                            value = null;
                            return true;
                        }
                        catch (JsonReaderParseException)
                        {
                            goto default;
                        }
                    case AtomElementType.NUMBER:
                    case AtomElementType.FLOAT:
                        atype = AssertReadNextAtomElement("期望是数字,包括整型 浮点型", out str, NUMBER_TYPES);
                        NumberStyles numStyles = GetExponentOrNotStyle(str, NUMBER_TYPES, atype);
                        bool ret;
                        IConvertible ivalue;
                        if (atype == AtomElementType.NUMBER)
                        {
                            ret = ReadNumber<short>(str, numStyles, out ivalue) ||
                                ReadNumber<int>(str, numStyles, out ivalue) ||
                                ReadNumber<long>(str, numStyles, out ivalue);
                            if (ret)
                            {
                                value = ivalue;
                                return true;
                            }
                        }

                        ret = ReadNumber<float>(str, numStyles, out ivalue) ||
                            ReadNumber<decimal>(str, numStyles, out ivalue) ||
                            ReadNumber<double>(str, numStyles, out ivalue);
                        if (ret)
                        {
                            value = ivalue;
                            return true;
                        }

                        goto default;
                    case AtomElementType.LITERAL:
                        SkipNext();
                        return true;
                    default:
                        return true;
                }
            }
            return base.OnReadObject(type, ref value, callback);
        }

        /// <summary>从当前流位置读取一个自定义对象,即{}包括的数据</summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public override bool ReadCustomObject(Type type, ref object value, ReadObjectCallback callback)
        {
            AtomElementType atype = AssertReadNextAtomElement("期望对象开始符号或null", AtomElementType.BRACE_OPEN, AtomElementType.NULL);
            if (atype == AtomElementType.NULL)
            {
                value = null;
                return true;
            }
            if (type == typeof(ReservedTypeClass) || !IsExactType(type))
            {
                string str;
                bool hasType = false;
                atype = AssertReadNextAtomElement(true, "期望是 __type 或者自定义对象结束符号", out str, AtomElementType.BRACE_CLOSE, AtomElementType.STRING);
                if (atype == AtomElementType.STRING)
                {
                    AssertReadNextAtomElement("期望是 __type", out str, AtomElementType.STRING);
                    AssertReadNextAtomElement("期望是 __type 后的冒号", AtomElementType.COLON);
                    if (str.ToLower() == "__type")
                    {
                        AssertReadNextAtomElement("期望是 __type 的值,具体的类型全名", out str, AtomElementType.STRING);
                        try
                        {
                            type = TypeX.GetType(str, true);
                            hasType = true;
                        }
                        catch { }
                        if (hasType)
                        {
                            Depth++;
                            WriteLog("ReadCustomObjectType", type.Name);
                            Depth--;
                        }
                    }
                }
                if (!hasType) //无效的类型以及非__type将创建字典,并将刚读取到的数据写入新创建的字典
                {
                    Depth++;
                    WriteLog("ReadCustomObjectType", "Read type fail");
                    Depth--;
                    Dictionary<string, object> dict = new Dictionary<string, object>();
                    if (atype == AtomElementType.STRING)
                    {
                        object obj = null;
                        if (!ReadObject(null, ref obj, callback)) return false;
                        dict.Add(str, obj);
                    }
                    value = dict;
                }
            }

            int d = ComplexObjectDepth++;
            bool ret = ComplexObjectDepthIsOverflow();
            if (ret) // 即使达到了读取深度限制,并且对象尚未创建,也创建类实例,以避免产生null
            {
                if (value == null)
                {
                    value = TypeX.CreateInstance(type);
                }
            }
            else
            {
                ret = base.ReadCustomObject(type, ref value, callback);
                if (ret && value == null) //已进入{开始读取对象成员 并完成,但是读取到的是null,当前的type没有任何成员,为确保再次序列化保持一致,需要给value创建实例
                {
                    value = TypeX.CreateInstance(type);
                }
            }
            int n = ComplexObjectDepth - d;
            if (n > 0) //尚未读到当前对象的结束符}
            {
                SkipNext(n);
            }
            else if (n < 0)
            {
                throw new JsonReaderAssertException(line, column, new AtomElementType[] { AtomElementType.BRACKET_CLOSE }, AtomElementType.NONE, "自定义对象解析异常,读取了过多的对象结束符:}");
            }
            return ret;
        }

        /// <summary>当前解析复合对象深度是否超出,用于避免循环引用可能引起的堆栈溢出,仅在Settings.RepeatedActionType是RepeatedAction.DepthLimit时才可能返回true</summary>
        /// <returns></returns>
        public bool ComplexObjectDepthIsOverflow()
        {
            return Settings.DuplicatedObjectWriteMode == DuplicatedObjectWriteMode.DepthLimit && ComplexObjectDepth > Settings.DepthLimit;
        }

        /// <summary>读取当前成员名称</summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <param name="members"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        protected override IObjectMemberInfo GetMemberBeforeRead(Type type, object value, IObjectMemberInfo[] members, int index)
        {
            IObjectMemberInfo ret = null;
            AtomElementType atype;
            string name;
            while (true)
            {
                atype = AssertReadNextAtomElement(true, "期望成员名称,逗号分割符,对象结束符", out name, MEMBERNAME_EXPECTED_TYPES); //预读 不移动位置
                switch (atype)
                {
                    case AtomElementType.COMMA:
                        AssertReadNextAtomElement("期望逗号分隔符", AtomElementType.COMMA);
                        break;
                    case AtomElementType.BRACE_CLOSE: //提前结束,不移动流位置
                        Depth--; //continue需要使Depth--
                        return null; //使父类上层调用处continue
                }
                atype = AssertReadNextAtomElement("期望成员名称", out name, AtomElementType.STRING);
                AssertReadNextAtomElement("期望成员名值分割符:冒号", AtomElementType.COLON);
                ret = GetMemberByName(members, name);
                if (ret != null)
                {
                    break;
                }
                SkipNext();
            }
            return ret;
        }

        /// <summary>从当前流位置读取成员值</summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <param name="member"></param>
        /// <param name="index"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        protected override bool OnReadMember(Type type, ref object value, IObjectMemberInfo member, int index, ReadObjectCallback callback)
        {
            if (!IsExactType(type)) //避免父类进入ReadType的调用
            {
                if (typeof(IDictionary).IsAssignableFrom(type)) //声明为无法实例化的类型,并且实现了IDictionary接口
                {
                    bool isGeneric = false;
                    if (type.IsGenericType)
                    {
                        Type[] genericTypes = type.GetGenericArguments();
                        if (genericTypes.Length == 2)
                        {
                            type = typeof(Dictionary<,>).MakeGenericType(genericTypes);
                            isGeneric = true;
                        }
                    }
                    if (!isGeneric)
                    {
                        type = typeof(Hashtable);
                    }
                }
                else if (typeof(IEnumerable).IsAssignableFrom(type)) //声明为无法实例化的类型,并且实现了IEnumerable接口
                {
                    bool isGeneric = false;
                    if (type.IsGenericType)
                    {
                        Type[] genericTypes = type.GetGenericArguments();
                        if (genericTypes.Length == 1)
                        {
                            type = typeof(List<>).MakeGenericType(genericTypes);
                            isGeneric = true;
                        }
                    }
                    if (!isGeneric)
                    {
                        type = typeof(ArrayList);
                    }
                }
                else
                {
                    //type = typeof(ReservedTypeClass); //注释是因为base.OnReadMember方法中已经没有ReadType的调用,将最终由OnReadObject方法处理
                }
            }
            return base.OnReadMember(type, ref value, member, index, callback);
        }

        /// <summary>表示类型是无法实例化的类型,用于避免父类CheckAndReadType中的ReadType被执行,因为json的类型标识是另外的格式</summary>
        private class ReservedTypeClass { }
        #endregion

        #region 方法
        /// <summary>读取多维数组的维度</summary>
        /// <returns></returns>
        protected override string ReadLengths()
        {
            String lengths = base.ReadLengths();
            //if (lengths.StartsWith("\"") || lengths.EndsWith("\""))
            //{
            // lengths = lengths.Substring(1, lengths.Length - 1);
            //}
            //lengths.Replace("\"", "");
            return lengths;
        }

        /// <summary>备份当前环境,用于临时切换数据流等</summary>
        /// <returns>本次备份项集合</returns>
        public override IDictionary<String, Object> Backup()
        {
            var dic = base.Backup();
            dic["Reader"] = Reader;

            return dic;
        }

        /// <summary>恢复最近一次备份</summary>
        /// <returns>本次还原项集合</returns>
        public override IDictionary<String, Object> Restore()
        {
            var dic = base.Restore();
            Reader = dic["Reader"] as TextReader;

            return dic;
        }
        #endregion

        #region 内部类
        /// <summary>原子元素类型</summary>
        public enum AtomElementType
        {
            /// <summary>无 一般表示结尾</summary>
            NONE,
            /// <summary>大括号开始 {</summary>
            BRACE_OPEN,
            /// <summary>大括号结束 }</summary>
            BRACE_CLOSE,
            /// <summary>方括号开始 [</summary>
            BRACKET_OPEN,
            /// <summary>方括号结束 ]</summary>
            BRACKET_CLOSE,
            /// <summary>冒号 :</summary>
            COLON,
            /// <summary>逗号 ,</summary>
            COMMA,
            /// <summary>字符串 "包含的</summary>
            STRING,
            #region 字面值部分
            /// <summary>字面值 无法识别的字面值</summary>
            LITERAL,
            /// <summary>字面值 true</summary>
            TRUE,
            /// <summary>字面值 false</summary>
            FALSE,
            /// <summary>字面值 null</summary>
            NULL,
            /// <summary>字面值 数字,非科学计数法表示的</summary>
            NUMBER,
            /// <summary>字面值 数字,科学计数发表示的</summary>
            NUMBER_EXP,
            /// <summary>字面值 浮点数,非科学计数法表示的浮点数</summary>
            FLOAT,
            /// <summary>字面值 浮点数,科学计数法表示的浮点数</summary>
            FLOAT_EXP
            #endregion
        }

        /// <summary>json reader断言异常,属于解析异常的一部分,主要是提供的数据不符合约定</summary>
        public class JsonReaderAssertException : JsonReaderParseException
        {
            /// <summary>断言异常的额外异常信息</summary>
            public string MessageInfo { get; protected set; }

            /// <summary>断言期望的元素类型</summary>
            public AtomElementType[] Expected { get; protected set; }

            /// <summary>断言实际得到的类型,如果期望类型中包含这个类型,即表示错误是非元素基础类型错误,而是由于元素格式不符合理想,比如期望是日期时间格式的字符串</summary>
            public AtomElementType Actual { get; protected set; }

            /// <summary>构造一个断言异常</summary>
            /// <param name="line"></param>
            /// <param name="column"></param>
            /// <param name="expected">期望的节点类型</param>
            /// <param name="actual">实际节点类型</param>
            /// <param name="messageInfo">额外的描述信息</param>
            public JsonReaderAssertException(long line, long column, AtomElementType[] expected, AtomElementType actual, string messageInfo)
                : base(line, column, null)
            {
                this.Expected = expected;
                this.Actual = actual;
                this.MessageInfo = messageInfo;
            }

            /// <summary>异常信息,包含额外信息</summary>
            public override string Message { get { return FormatMessage(Line, Column, Expected, Actual, MessageInfo); } }

            /// <summary>获取相似参数下JsonReaderAssertException类的异常信息,在不需要JsonReaderAssertException异常,但需要异常信息时使用</summary>
            /// <param name="line"></param>
            /// <param name="column"></param>
            /// <param name="expected"></param>
            /// <param name="actual"></param>
            /// <param name="messageInfo"></param>
            /// <returns></returns>
            public static string FormatMessage(long line, long column, AtomElementType[] expected, AtomElementType actual, string messageInfo)
            {
                return string.Format("在行{0},字符{1}期望是{2} 实际是{3} 额外信息:{4}", line, column,
                        string.Join(",", Array.ConvertAll<AtomElementType, string>(expected, e => GetAtomElementTypeMessageString(e))),
                        GetAtomElementTypeMessageString(actual),
                        messageInfo
                        );
            }

            static string GetAtomElementTypeMessageString(AtomElementType t)
            {
                switch (t)
                {
                    case AtomElementType.NONE:
                        return "未知";
                    case AtomElementType.BRACE_OPEN:
                        return "{";
                    case AtomElementType.BRACE_CLOSE:
                        return "}";
                    case AtomElementType.BRACKET_OPEN:
                        return "[";
                    case AtomElementType.BRACKET_CLOSE:
                        return "]";
                    case AtomElementType.COLON:
                        return "冒号";
                    case AtomElementType.COMMA:
                        return "逗号";
                    case AtomElementType.STRING:
                        return "字符串";
                    case AtomElementType.LITERAL:
                        return "字面值";
                    case AtomElementType.TRUE:
                        return "true";
                    case AtomElementType.FALSE:
                        return "false";
                    case AtomElementType.NULL:
                        return "null";
                    case AtomElementType.NUMBER:
                        return "数字";
                    case AtomElementType.NUMBER_EXP:
                        return "数字(科学计数法)";
                    case AtomElementType.FLOAT:
                        return "浮点数";
                    case AtomElementType.FLOAT_EXP:
                        return "浮点数(科学计数法)";
                    default:
                        goto case AtomElementType.NONE;
                }

            }
        }
        #endregion
    }
}