📄 jsonreader.cs
字号:
else
{
// none found
memberType = null;
}
}
/// <summary>
/// Helper method to set value of either property or field
/// </summary>
/// <param name="result"></param>
/// <param name="memberType"></param>
/// <param name="memberInfo"></param>
/// <param name="value"></param>
private void SetMemberValue(Object result, Type memberType, MemberInfo memberInfo, object value)
{
if (memberInfo is PropertyInfo)
{
// set value of public property
((PropertyInfo)memberInfo).SetValue(
result,
JsonReader.CoerceType(memberType, value, this.index, this.AllowNullValueTypes),
null);
}
else if (memberInfo is FieldInfo)
{
// set value of public field
((FieldInfo)memberInfo).SetValue(
result,
JsonReader.CoerceType(memberType, value, this.index, this.AllowNullValueTypes));
}
// all other values are ignored
}
#endregion Object Methods
#region Type Methods
public static object CoerceType(Type targetType, object value)
{
return JsonReader.CoerceType(targetType, value, -1, false);
}
private static object CoerceType(Type targetType, object value, int index, bool allowNullValueTypes)
{
bool isNullable = JsonReader.IsNullable(targetType);
if (value == null)
{
if (allowNullValueTypes &&
targetType.IsValueType &&
!isNullable)
{
throw new JsonDeserializationException(String.Format(JsonReader.ErrorNullValueType, targetType.FullName), index);
}
return value;
}
if (isNullable)
{
// nullable types have a real underlying struct
Type[] genericArgs = targetType.GetGenericArguments();
if (genericArgs.Length == 1)
{
targetType = genericArgs[0];
}
}
Type actualType = value.GetType();
if (targetType.IsAssignableFrom(actualType))
{
return value;
}
if (targetType.IsEnum)
{
if (!Enum.IsDefined(targetType, value))
{
// if isn't a defined value perhaps it is the JsonName
foreach (FieldInfo field in targetType.GetFields())
{
string jsonName = JsonNameAttribute.GetJsonName(field);
if (((string)value).Equals(jsonName))
{
value = field.Name;
break;
}
}
}
if (value is String)
{
return Enum.Parse(targetType, (string)value);
}
else
{
return Convert.ChangeType(value, targetType);
}
}
if (actualType.IsArray && !targetType.IsArray)
{
return JsonReader.CoerceArray(targetType, actualType, value, index, allowNullValueTypes);
}
if (value is String)
{
if (targetType == typeof(DateTime))
{
DateTime date;
if (DateTime.TryParse(
(string)value,
DateTimeFormatInfo.InvariantInfo,
DateTimeStyles.RoundtripKind|DateTimeStyles.AllowWhiteSpaces|DateTimeStyles.NoCurrentDateDefault,
out date))
{
return date;
}
}
else if (targetType == typeof(Guid))
{
// try-catch is pointless since will throw upon generic conversion
return new Guid((string)value);
}
else if (targetType == typeof(Uri))
{
Uri uri;
if (Uri.TryCreate((string)value, UriKind.RelativeOrAbsolute, out uri))
{
return uri;
}
}
else if (targetType == typeof(Version))
{
// try-catch is pointless since will throw upon generic conversion
return new Version((string)value);
}
}
else if (targetType == typeof(TimeSpan))
{
return new TimeSpan((long)JsonReader.CoerceType(typeof(Int64), value, index, allowNullValueTypes));
}
TypeConverter converter = TypeDescriptor.GetConverter(targetType);
if (converter.CanConvertFrom(actualType))
{
return converter.ConvertFrom(value);
}
converter = TypeDescriptor.GetConverter(actualType);
if (converter.CanConvertTo(targetType))
{
return converter.ConvertTo(value, targetType);
}
return Convert.ChangeType(value, targetType);
}
private static object CoerceArray(Type targetType, Type arrayType, object value, int index, bool allowNullValueTypes)
{
// targetType serializes as a JSON array but is not an array
// assume is an ICollection / IEnumerable with AddRange, Add,
// or custom Constructor with which we can populate it
ConstructorInfo ctor = targetType.GetConstructor(Type.EmptyTypes);
if (ctor == null)
{
throw new JsonDeserializationException(JsonReader.ErrorDefaultCtor, index);
}
object collection = ctor.Invoke(null);
Array arrayValue = (Array)value;
// many ICollection types have an AddRange method
// which adds all items at once
MethodInfo method = targetType.GetMethod("AddRange");
ParameterInfo[] parameters = (method == null) ?
null : method.GetParameters();
Type paramType = (parameters == null || parameters.Length != 1) ?
null : parameters[0].ParameterType;
if (paramType != null &&
paramType.IsAssignableFrom(arrayType))
{
// add all members in one method
method.Invoke(
collection,
new object[] { arrayValue });
return collection;
}
else
{
// many ICollection types have an Add method
// which adds items one at a time
method = targetType.GetMethod("Add");
parameters = (method == null) ?
null : method.GetParameters();
paramType = (parameters == null || parameters.Length != 1) ?
null : parameters[0].ParameterType;
if (paramType != null)
{
// loop through adding items to collection
foreach (object item in arrayValue)
{
method.Invoke(
collection,
new object[] {
JsonReader.CoerceType(paramType, item, index, allowNullValueTypes)
});
}
return collection;
}
}
// many ICollection types take an IEnumerable or ICollection
// as a constructor argument. look through constructors for
// a compatible match.
ConstructorInfo[] ctors = targetType.GetConstructors();
foreach (ConstructorInfo ctor2 in ctors)
{
ParameterInfo[] paramList = ctor2.GetParameters();
if (paramList.Length == 1 &&
paramList[0].ParameterType.IsAssignableFrom(arrayType))
{
try
{
// invoke first constructor that can take this value as an argument
return ctor2.Invoke(
new object[] { value }
);
}
catch
{
// there might exist a better match
continue;
}
}
}
return Convert.ChangeType(value, targetType);
}
private static bool IsNullable(Type type)
{
return type.IsGenericType && (typeof(Nullable<>) == type.GetGenericTypeDefinition());
}
#endregion Type Methods
#region Tokenizing Methods
private JsonToken Tokenize()
{
if (this.index >= this.SourceLength)
{
return JsonToken.End;
}
// skip whitespace
while (Char.IsWhiteSpace(this.Source[this.index]))
{
this.index++;
if (this.index >= this.SourceLength)
{
return JsonToken.End;
}
}
#region Skip Comments
// skip block and line comments
if (this.Source[this.index] == JsonReader.CommentStart[0])
{
if (this.index+1 >= this.SourceLength)
{
throw new JsonDeserializationException(JsonReader.ErrorUnrecognizedToken, this.index);
}
// skip over first char of comment start
this.index++;
bool isBlockComment = false;
if (this.Source[this.index] == JsonReader.CommentStart[1])
{
isBlockComment = true;
}
else if (this.Source[this.index] != JsonReader.CommentLine[1])
{
throw new JsonDeserializationException(JsonReader.ErrorUnrecognizedToken, this.index);
}
// skip over second char of comment start
this.index++;
if (isBlockComment)
{
// store index for unterminated case
int commentStart = this.index-2;
if (this.index+1 >= this.SourceLength)
{
throw new JsonDeserializationException(JsonReader.ErrorUnterminatedComment, commentStart);
}
// skip over everything until reach block comment ending
while (this.Source[this.index] != JsonReader.CommentEnd[0] ||
this.Source[this.index+1] != JsonReader.CommentEnd[1])
{
this.index++;
if (this.index+1 >= this.SourceLength)
{
throw new JsonDeserializationException(JsonReader.ErrorUnterminatedComment, commentStart);
}
}
// skip block comment end token
this.index += 2;
if (this.index >= this.SourceLength)
{
return JsonToken.End;
}
}
else
{
// skip over everything until reach line ending
while (JsonReader.LineEndings.IndexOf(this.Source[this.index]) < 0)
{
this.index++;
if (this.index >= this.SourceLength)
{
return JsonToken.End;
}
}
}
// skip whitespace again
while (Char.IsWhiteSpace(this.Source[this.index]))
{
this.index++;
if (this.index >= this.SourceLength)
{
return JsonToken.End;
}
}
}
#endregion Skip Comments
// consume positive signing (as is extraneous)
if (this.Source[this.index] == JsonReader.OperatorUnaryPlus)
{
this.index++;
if (this.index >= this.SourceLength)
{
return JsonToken.End;
}
}
switch (this.Source[this.index])
{
case JsonReader.OperatorArrayStart:
{
return JsonToken.ArrayStart;
}
case JsonReader.OperatorArrayEnd:
{
return JsonToken.ArrayEnd;
}
case JsonReader.OperatorObjectStart:
{
return JsonToken.ObjectStart;
}
case JsonReader.OperatorObjectEnd:
{
return JsonToken.ObjectEnd;
}
case JsonReader.OperatorStringDelim:
case JsonReader.OperatorStringDelimAlt:
{
return JsonToken.String;
}
case JsonReader.OperatorValueDelim:
{
return JsonToken.ValueDelim;
}
case JsonReader.OperatorNameDelim:
{
return JsonToken.NameDelim;
}
default:
{
break;
}
}
// number
if (Char.IsDigit(this.Source[this.index]) ||
((this.Source[this.index] == JsonReader.OperatorNegate) && (this.index+1 < this.SourceLength) && Char.IsDigit(this.Source[this.index+1])))
{
return JsonToken.Number;
}
// "false" literal
if (this.MatchLiteral(JsonReader.LiteralFalse))
{
return JsonToken.False;
}
// "true" literal
if (this.MatchLiteral(JsonReader.LiteralTrue))
{
return JsonToken.True;
}
// "null" literal
if (this.MatchLiteral(JsonReader.LiteralNull))
{
return JsonToken.Null;
}
// "NaN" literal
if (this.MatchLiteral(JsonReader.LiteralNotANumber))
{
return JsonToken.NaN;
}
// "Infinity" literal
if (this.MatchLiteral(JsonReader.LiteralPositiveInfinity))
{
return JsonToken.PositiveInfinity;
}
// "-Infinity" literal
if (this.MatchLiteral(JsonReader.LiteralNegativeInfinity))
{
return JsonToken.NegativeInfinity;
}
throw new JsonDeserializationException(JsonReader.ErrorUnrecognizedToken, this.index);
}
/// <summary>
/// Determines if the next token is the given literal
/// </summary>
/// <param name="literal"></param>
/// <returns></returns>
private bool MatchLiteral(string literal)
{
int literalLength = literal.Length;
for (int i=0, j=this.index; i<literalLength && j<this.SourceLength; i++, j++)
{
if (literal[i] != this.Source[j])
{
return false;
}
}
return true;
}
#endregion Tokenizing Methods
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -