📄 jsonreader.cs
字号:
}
return jsArray.ToArray();
}
private object ReadString(Type expectedType)
{
if (this.Source[this.index] != JsonReader.OperatorStringDelim &&
this.Source[this.index] != JsonReader.OperatorStringDelimAlt)
{
throw new JsonDeserializationException(JsonReader.ErrorExpectedString, this.index);
}
char startStringDelim = this.Source[this.index];
// consume opening quote
this.index++;
if (this.index >= this.SourceLength)
{
throw new JsonDeserializationException(JsonReader.ErrorUnterminatedString, this.index);
}
int start = this.index;
StringBuilder builder = new StringBuilder();
while (this.Source[this.index] != startStringDelim)
{
if (this.Source[this.index] == JsonReader.OperatorCharEscape)
{
// copy chunk before decoding
builder.Append(this.Source, start, this.index - start);
// consume escape char
this.index++;
if (this.index >= this.SourceLength)
{
throw new JsonDeserializationException(JsonReader.ErrorUnterminatedString, this.index);
}
// decode
switch (this.Source[this.index])
{
case '0':
{
// don't allow NULL char '\0'
// causes CStrings to terminate
break;
}
case 'b':
{
// backspace
builder.Append('\b');
break;
}
case 'f':
{
// formfeed
builder.Append('\f');
break;
}
case 'n':
{
// newline
builder.Append('\n');
break;
}
case 'r':
{
// carriage return
builder.Append('\r');
break;
}
case 't':
{
// tab
builder.Append('\t');
break;
}
case 'u':
{
// Unicode escape sequence
// e.g. Copyright: "\u00A9"
// unicode ordinal
int utf16;
if (this.index+4 < this.SourceLength &&
Int32.TryParse(
this.Source.Substring(this.index+1, 4),
NumberStyles.AllowHexSpecifier,
NumberFormatInfo.InvariantInfo,
out utf16))
{
builder.Append(Char.ConvertFromUtf32(utf16));
this.index += 4;
}
else
{
// using FireFox style recovery, if not a valid hex
// escape sequence then treat as single escaped 'u'
// followed by rest of string
builder.Append(this.Source[this.index]);
}
break;
}
default:
{
builder.Append(Source[this.index]);
break;
}
}
this.index++;
if (this.index >= this.SourceLength)
{
throw new JsonDeserializationException(JsonReader.ErrorUnterminatedString, this.index);
}
start = this.index;
}
else
{
// next char
index++;
if (this.index >= this.SourceLength)
{
throw new JsonDeserializationException(JsonReader.ErrorUnterminatedString, this.index);
}
}
}
// copy rest of string
builder.Append(this.Source, start, this.index-start);
// consume closing quote
this.index++;
if (expectedType != null && expectedType != typeof(String))
{
return JsonReader.CoerceType(expectedType, builder.ToString(), this.index, this.AllowNullValueTypes);
}
return builder.ToString();
}
private object ReadNumber(Type expectedType)
{
bool hasDecimal = false;
bool hasExponent = false;
int start = this.index;
int precision = 0;
int exponent = 0;
// optional minus part
if (this.Source[this.index] == JsonReader.OperatorNegate)
{
// consume sign
this.index++;
if (this.index >= this.SourceLength || !Char.IsDigit(this.Source[this.index]))
throw new JsonDeserializationException(JsonReader.ErrorIllegalNumber, this.index);
}
// integer part
while ((this.index < this.SourceLength) && Char.IsDigit(this.Source[this.index]))
{
// consume digit
this.index++;
}
// optional decimal part
if ((this.index < this.SourceLength) && (this.Source[this.index] == '.'))
{
hasDecimal = true;
// consume decimal
this.index++;
if (this.index >= this.SourceLength || !Char.IsDigit(this.Source[this.index]))
{
throw new JsonDeserializationException(JsonReader.ErrorIllegalNumber, this.index);
}
// fraction part
while (this.index < this.SourceLength && Char.IsDigit(this.Source[this.index]))
{
// consume digit
this.index++;
}
}
// note the number of significant digits
precision = this.index-start - (hasDecimal ? 1 : 0);
// optional exponent part
if (this.index < this.SourceLength && (this.Source[this.index] == 'e' || this.Source[this.index] == 'E'))
{
hasExponent = true;
// consume 'e'
this.index++;
if (this.index >= this.SourceLength)
{
throw new JsonDeserializationException(JsonReader.ErrorIllegalNumber, this.index);
}
int expStart = this.index;
// optional minus/plus part
if (this.Source[this.index] == JsonReader.OperatorNegate || this.Source[this.index] == JsonReader.OperatorUnaryPlus)
{
// consume sign
this.index++;
if (this.index >= this.SourceLength || !Char.IsDigit(this.Source[this.index]))
{
throw new JsonDeserializationException(JsonReader.ErrorIllegalNumber, this.index);
}
}
else
{
if (!Char.IsDigit(this.Source[this.index]))
{
throw new JsonDeserializationException(JsonReader.ErrorIllegalNumber, this.index);
}
}
// exp part
while (this.index < this.SourceLength && Char.IsDigit(this.Source[this.index]))
{
// consume digit
this.index++;
}
Int32.TryParse(this.Source.Substring(expStart, this.index-expStart), NumberStyles.Integer,
NumberFormatInfo.InvariantInfo, out exponent);
}
// at this point, we have the full number string and know its characteristics
string numberString = this.Source.Substring(start, this.index - start);
if (!hasDecimal && !hasExponent && precision < 19)
{
// is Integer value
// parse as most flexible
decimal number = Decimal.Parse(
numberString,
NumberStyles.Integer,
NumberFormatInfo.InvariantInfo);
if (expectedType != null)
{
return JsonReader.CoerceType(expectedType, number, this.index, this.AllowNullValueTypes);
}
if (number >= Int32.MinValue && number <= Int32.MaxValue)
{
// use most common
return (int)number;
}
if (number >= Int64.MinValue && number <= Int64.MaxValue)
{
// use more flexible
return (long)number;
}
// use most flexible
return number;
}
else
{
// is Floating Point value
if (expectedType == typeof(Decimal))
{
// special case since Double does not convert to Decimal
return Decimal.Parse(
numberString,
NumberStyles.Float,
NumberFormatInfo.InvariantInfo);
}
// use native EcmaScript number (IEEE 754)
double number = Double.Parse(
numberString,
NumberStyles.Float,
NumberFormatInfo.InvariantInfo);
if (expectedType != null)
{
return JsonReader.CoerceType(expectedType, number, this.index, this.AllowNullValueTypes);
}
return number;
}
}
#endregion Parsing Methods
#region Object Methods
/// <summary>
/// If a Type Hint is present then this method attempts to
/// use it and move any previously parsed data over.
/// </summary>
/// <param name="objectType">reference to the objectType</param>
/// <param name="memberMap">reference to the memberMap</param>
/// <param name="result">the previous result</param>
/// <param name="typeInfo">the type info string to use</param>
/// <returns></returns>
private Object ProcessTypeHint(
ref Type objectType,
ref Dictionary<string, MemberInfo> memberMap,
IDictionary result,
string typeInfo)
{
if (String.IsNullOrEmpty(typeInfo))
{
return result;
}
Type hintedType = Type.GetType(typeInfo, false);
if (hintedType == null)
{
return result;
}
objectType = hintedType;
object newResult = this.InstantiateObject(hintedType, ref memberMap);
if (memberMap != null)
{
Type memberType;
MemberInfo memberInfo;
// copy any values into new object
foreach (object key in result.Keys)
{
JsonReader.GetMemberInfo(memberMap, key as String, out memberType, out memberInfo);
this.SetMemberValue(newResult, memberType, memberInfo, result[key]);
}
}
return newResult;
}
private Object InstantiateObject(Type objectType, ref Dictionary<string, MemberInfo> memberMap)
{
Object result;
ConstructorInfo ctor = objectType.GetConstructor(Type.EmptyTypes);
if (ctor == null)
{
throw new JsonDeserializationException(JsonReader.ErrorDefaultCtor, this.index);
}
result = ctor.Invoke(null);
// don't incurr the cost of member map if a dictionary
if (!typeof(IDictionary).IsAssignableFrom(objectType))
{
memberMap = this.CreateMemberMap(objectType);
}
return result;
}
private Dictionary<string, MemberInfo> CreateMemberMap(Type objectType)
{
if (this.MemberMapCache == null)
{
// instantiate space for cache
this.MemberMapCache = new Dictionary<Type, Dictionary<string, MemberInfo>>();
}
else if (this.MemberMapCache.ContainsKey(objectType))
{
// map was stored in cache
return this.MemberMapCache[objectType];
}
// create a new map
Dictionary<string, MemberInfo> memberMap = new Dictionary<string, MemberInfo>();
// load properties into property map
PropertyInfo[] properties = objectType.GetProperties();
foreach (PropertyInfo info in properties)
{
if (!info.CanRead || !info.CanWrite)
{
continue;
}
if (JsonIgnoreAttribute.IsJsonIgnore(info))
{
continue;
}
string jsonName = JsonNameAttribute.GetJsonName(info);
if (String.IsNullOrEmpty(jsonName))
{
memberMap[info.Name] = info;
}
else
{
memberMap[jsonName] = info;
}
}
// load public fields into property map
FieldInfo[] fields = objectType.GetFields();
foreach (FieldInfo info in fields)
{
if (!info.IsPublic)
{
continue;
}
if (JsonIgnoreAttribute.IsJsonIgnore(info))
{
continue;
}
string jsonName = JsonNameAttribute.GetJsonName(info);
if (String.IsNullOrEmpty(jsonName))
{
memberMap[info.Name] = info;
}
else
{
memberMap[jsonName] = info;
}
}
// store in cache for repeated usage
this.MemberMapCache[objectType] = memberMap;
return memberMap;
}
private static void GetMemberInfo(
Dictionary<string, MemberInfo> memberMap,
string memberName,
out Type memberType,
out MemberInfo memberInfo)
{
memberType = null;
memberInfo = null;
if (memberMap != null &&
memberMap.ContainsKey(memberName))
{
// Check properties for object member
memberInfo = memberMap[memberName];
if (memberInfo is PropertyInfo)
{
// maps to public property
memberType = ((PropertyInfo)memberInfo).PropertyType;
}
else if (memberInfo is FieldInfo)
{
// maps to public field
memberType = ((FieldInfo)memberInfo).FieldType;
}
else
{
// none found
memberType = null;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -