<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />

ConvertUtils

static class ConvertUtils
using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Numerics; using System.Reflection; namespace Newtonsoft.Json.Utilities { internal static class ConvertUtils { internal readonly struct TypeConvertKey : IEquatable<TypeConvertKey> { public Type InitialType { get; } public Type TargetType { get; } public TypeConvertKey(Type initialType, Type targetType) { InitialType = initialType; TargetType = targetType; } public override int GetHashCode() { return InitialType.GetHashCode() ^ TargetType.GetHashCode(); } public override bool Equals(object obj) { if (!(obj is TypeConvertKey)) return false; return Equals((TypeConvertKey)obj); } public bool Equals(TypeConvertKey other) { if (InitialType == other.InitialType) return TargetType == other.TargetType; return false; } } internal enum ConvertResult { Success, CannotConvertNull, NotInstantiableType, NoValidConversion } private static readonly Dictionary<Type, PrimitiveTypeCode> TypeCodeMap = new Dictionary<Type, PrimitiveTypeCode> { { typeof(char), PrimitiveTypeCode.Char }, { typeof(char?), PrimitiveTypeCode.CharNullable }, { typeof(bool), PrimitiveTypeCode.Boolean }, { typeof(bool?), PrimitiveTypeCode.BooleanNullable }, { typeof(sbyte), PrimitiveTypeCode.SByte }, { typeof(sbyte?), PrimitiveTypeCode.SByteNullable }, { typeof(short), PrimitiveTypeCode.Int16 }, { typeof(short?), PrimitiveTypeCode.Int16Nullable }, { typeof(ushort), PrimitiveTypeCode.UInt16 }, { typeof(ushort?), PrimitiveTypeCode.UInt16Nullable }, { typeof(int), PrimitiveTypeCode.Int32 }, { typeof(int?), PrimitiveTypeCode.Int32Nullable }, { typeof(byte), PrimitiveTypeCode.Byte }, { typeof(byte?), PrimitiveTypeCode.ByteNullable }, { typeof(uint), PrimitiveTypeCode.UInt32 }, { typeof(uint?), PrimitiveTypeCode.UInt32Nullable }, { typeof(long), PrimitiveTypeCode.Int64 }, { typeof(long?), PrimitiveTypeCode.Int64Nullable }, { typeof(ulong), PrimitiveTypeCode.UInt64 }, { typeof(ulong?), PrimitiveTypeCode.UInt64Nullable }, { typeof(float), PrimitiveTypeCode.Single }, { typeof(float?), PrimitiveTypeCode.SingleNullable }, { typeof(double), PrimitiveTypeCode.Double }, { typeof(double?), PrimitiveTypeCode.DoubleNullable }, { typeof(DateTime), PrimitiveTypeCode.DateTime }, { typeof(DateTime?), PrimitiveTypeCode.DateTimeNullable }, { typeof(DateTimeOffset), PrimitiveTypeCode.DateTimeOffset }, { typeof(DateTimeOffset?), PrimitiveTypeCode.DateTimeOffsetNullable }, { typeof(decimal), PrimitiveTypeCode.Decimal }, { typeof(decimal?), PrimitiveTypeCode.DecimalNullable }, { typeof(Guid), PrimitiveTypeCode.Guid }, { typeof(Guid?), PrimitiveTypeCode.GuidNullable }, { typeof(TimeSpan), PrimitiveTypeCode.TimeSpan }, { typeof(TimeSpan?), PrimitiveTypeCode.TimeSpanNullable }, { typeof(BigInteger), PrimitiveTypeCode.BigInteger }, { typeof(BigInteger?), PrimitiveTypeCode.BigIntegerNullable }, { typeof(Uri), PrimitiveTypeCode.Uri }, { typeof(string), PrimitiveTypeCode.String }, { typeof(byte[]), PrimitiveTypeCode.Bytes }, { typeof(DBNull), PrimitiveTypeCode.DBNull } }; private static readonly TypeInformation[] PrimitiveTypeCodes = new TypeInformation[19] { new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Empty }, new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Object }, new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.DBNull }, new TypeInformation { Type = typeof(bool), TypeCode = PrimitiveTypeCode.Boolean }, new TypeInformation { Type = typeof(char), TypeCode = PrimitiveTypeCode.Char }, new TypeInformation { Type = typeof(sbyte), TypeCode = PrimitiveTypeCode.SByte }, new TypeInformation { Type = typeof(byte), TypeCode = PrimitiveTypeCode.Byte }, new TypeInformation { Type = typeof(short), TypeCode = PrimitiveTypeCode.Int16 }, new TypeInformation { Type = typeof(ushort), TypeCode = PrimitiveTypeCode.UInt16 }, new TypeInformation { Type = typeof(int), TypeCode = PrimitiveTypeCode.Int32 }, new TypeInformation { Type = typeof(uint), TypeCode = PrimitiveTypeCode.UInt32 }, new TypeInformation { Type = typeof(long), TypeCode = PrimitiveTypeCode.Int64 }, new TypeInformation { Type = typeof(ulong), TypeCode = PrimitiveTypeCode.UInt64 }, new TypeInformation { Type = typeof(float), TypeCode = PrimitiveTypeCode.Single }, new TypeInformation { Type = typeof(double), TypeCode = PrimitiveTypeCode.Double }, new TypeInformation { Type = typeof(decimal), TypeCode = PrimitiveTypeCode.Decimal }, new TypeInformation { Type = typeof(DateTime), TypeCode = PrimitiveTypeCode.DateTime }, new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Empty }, new TypeInformation { Type = typeof(string), TypeCode = PrimitiveTypeCode.String } }; private static readonly ThreadSafeStore<TypeConvertKey, Func<object, object>> CastConverters = new ThreadSafeStore<TypeConvertKey, Func<object, object>>(CreateCastConverter); public static PrimitiveTypeCode GetTypeCode(Type t) { bool isEnum; return GetTypeCode(t, out isEnum); } public static PrimitiveTypeCode GetTypeCode(Type t, out bool isEnum) { if (TypeCodeMap.TryGetValue(t, out PrimitiveTypeCode value)) { isEnum = false; return value; } if (t.IsEnum()) { isEnum = true; return GetTypeCode(Enum.GetUnderlyingType(t)); } if (ReflectionUtils.IsNullableType(t)) { Type underlyingType = Nullable.GetUnderlyingType(t); if (underlyingType.IsEnum()) { Type t2 = typeof(Nullable<>).MakeGenericType(Enum.GetUnderlyingType(underlyingType)); isEnum = true; return GetTypeCode(t2); } } isEnum = false; return PrimitiveTypeCode.Object; } public static TypeInformation GetTypeInformation(IConvertible convertable) { return PrimitiveTypeCodes[(int)convertable.GetTypeCode()]; } public static bool IsConvertible(Type t) { return typeof(IConvertible).IsAssignableFrom(t); } public static TimeSpan ParseTimeSpan(string input) { return TimeSpan.Parse(input, CultureInfo.InvariantCulture); } private static Func<object, object> CreateCastConverter(TypeConvertKey t) { MethodInfo methodInfo = t.TargetType.GetMethod("op_Implicit", new Type[1] { t.InitialType }) ?? t.TargetType.GetMethod("op_Explicit", new Type[1] { t.InitialType }); if (methodInfo == (MethodInfo)null) return null; MethodCall<object, object> call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(methodInfo); return (object o) => call(null, o); } internal static BigInteger ToBigInteger(object value) { object obj; if ((obj = value) is BigInteger) return (BigInteger)obj; string value2; if ((value2 = (value as string)) != null) return BigInteger.Parse(value2, CultureInfo.InvariantCulture); if ((obj = value) is float) { float value3 = (float)obj; return new BigInteger(value3); } if ((obj = value) is double) { double value4 = (double)obj; return new BigInteger(value4); } if ((obj = value) is decimal) { decimal value5 = (decimal)obj; return new BigInteger(value5); } if ((obj = value) is int) { int value6 = (int)obj; return new BigInteger(value6); } if ((obj = value) is long) { long value7 = (long)obj; return new BigInteger(value7); } if ((obj = value) is uint) { uint value8 = (uint)obj; return new BigInteger(value8); } if ((obj = value) is ulong) { ulong value9 = (ulong)obj; return new BigInteger(value9); } byte[] value10; if ((value10 = (value as byte[])) != null) return new BigInteger(value10); throw new InvalidCastException("Cannot convert {0} to BigInteger.".FormatWith(CultureInfo.InvariantCulture, value.GetType())); } public static object FromBigInteger(BigInteger i, Type targetType) { if (targetType == typeof(decimal)) return (decimal)i; if (targetType == typeof(double)) return (double)i; if (targetType == typeof(float)) return (float)i; if (targetType == typeof(ulong)) return (ulong)i; if (!(targetType == typeof(bool))) try { return System.Convert.ChangeType((long)i, targetType, CultureInfo.InvariantCulture); } catch (Exception innerException) { throw new InvalidOperationException("Can not convert from BigInteger to {0}.".FormatWith(CultureInfo.InvariantCulture, targetType), innerException); } return i != 0; } public static object Convert(object initialValue, CultureInfo culture, Type targetType) { object value; switch (TryConvertInternal(initialValue, culture, targetType, out value)) { case ConvertResult.Success: return value; case ConvertResult.CannotConvertNull: throw new Exception("Can not convert null {0} into non-nullable {1}.".FormatWith(CultureInfo.InvariantCulture, initialValue.GetType(), targetType)); case ConvertResult.NotInstantiableType: throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), "targetType"); case ConvertResult.NoValidConversion: throw new InvalidOperationException("Can not convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, initialValue.GetType(), targetType)); default: throw new InvalidOperationException("Unexpected conversion result."); } } private static bool TryConvert(object initialValue, CultureInfo culture, Type targetType, out object value) { try { if (TryConvertInternal(initialValue, culture, targetType, out value) != 0) { value = null; return false; } return true; } catch { value = null; return false; } } private static ConvertResult TryConvertInternal(object initialValue, CultureInfo culture, Type targetType, out object value) { if (initialValue == null) throw new ArgumentNullException("initialValue"); if (ReflectionUtils.IsNullableType(targetType)) targetType = Nullable.GetUnderlyingType(targetType); Type type = initialValue.GetType(); if (targetType == type) { value = initialValue; return ConvertResult.Success; } if (IsConvertible(initialValue.GetType()) && IsConvertible(targetType)) { if (targetType.IsEnum()) { if (initialValue is string) { value = Enum.Parse(targetType, initialValue.ToString(), true); return ConvertResult.Success; } if (IsInteger(initialValue)) { value = Enum.ToObject(targetType, initialValue); return ConvertResult.Success; } } value = System.Convert.ChangeType(initialValue, targetType, culture); return ConvertResult.Success; } object obj; if ((obj = initialValue) is DateTime) { DateTime dateTime = (DateTime)obj; if (targetType == typeof(DateTimeOffset)) { value = new DateTimeOffset(dateTime); return ConvertResult.Success; } } byte[] b; if ((b = (initialValue as byte[])) != null && targetType == typeof(Guid)) { value = new Guid(b); return ConvertResult.Success; } if ((obj = initialValue) is Guid) { Guid guid = (Guid)obj; if (targetType == typeof(byte[])) { value = guid.ToByteArray(); return ConvertResult.Success; } } string text; if ((text = (initialValue as string)) != null) { if (targetType == typeof(Guid)) { value = new Guid(text); return ConvertResult.Success; } if (targetType == typeof(Uri)) { value = new Uri(text, UriKind.RelativeOrAbsolute); return ConvertResult.Success; } if (targetType == typeof(TimeSpan)) { value = ParseTimeSpan(text); return ConvertResult.Success; } if (targetType == typeof(byte[])) { value = System.Convert.FromBase64String(text); return ConvertResult.Success; } if (targetType == typeof(Version)) { if (VersionTryParse(text, out Version result)) { value = result; return ConvertResult.Success; } value = null; return ConvertResult.NoValidConversion; } if (typeof(Type).IsAssignableFrom(targetType)) { value = Type.GetType(text, true); return ConvertResult.Success; } } if (targetType == typeof(BigInteger)) { value = ToBigInteger(initialValue); return ConvertResult.Success; } if ((obj = initialValue) is BigInteger) { BigInteger i = (BigInteger)obj; value = FromBigInteger(i, targetType); return ConvertResult.Success; } TypeConverter converter = TypeDescriptor.GetConverter(type); if (converter != null && converter.CanConvertTo(targetType)) { value = converter.ConvertTo(null, culture, initialValue, targetType); return ConvertResult.Success; } TypeConverter converter2 = TypeDescriptor.GetConverter(targetType); if (converter2 != null && converter2.CanConvertFrom(type)) { value = converter2.ConvertFrom(null, culture, initialValue); return ConvertResult.Success; } if (initialValue == DBNull.Value) { if (ReflectionUtils.IsNullable(targetType)) { value = EnsureTypeAssignable(null, type, targetType); return ConvertResult.Success; } value = null; return ConvertResult.CannotConvertNull; } if (targetType.IsInterface() || targetType.IsGenericTypeDefinition() || targetType.IsAbstract()) { value = null; return ConvertResult.NotInstantiableType; } value = null; return ConvertResult.NoValidConversion; } public static object ConvertOrCast(object initialValue, CultureInfo culture, Type targetType) { if (targetType == typeof(object)) return initialValue; if (initialValue == null && ReflectionUtils.IsNullable(targetType)) return null; if (TryConvert(initialValue, culture, targetType, out object value)) return value; return EnsureTypeAssignable(initialValue, ReflectionUtils.GetObjectType(initialValue), targetType); } private static object EnsureTypeAssignable(object value, Type initialType, Type targetType) { Type type = value?.GetType(); if (value != null) { if (targetType.IsAssignableFrom(type)) return value; Func<object, object> func = CastConverters.Get(new TypeConvertKey(type, targetType)); if (func != null) return func(value); } else if (ReflectionUtils.IsNullable(targetType)) { return null; } throw new ArgumentException("Could not cast or convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, initialType?.ToString() ?? "{null}", targetType)); } public static bool VersionTryParse(string input, out Version result) { return Version.TryParse(input, out result); } public static bool IsInteger(object value) { switch (GetTypeCode(value.GetType())) { case PrimitiveTypeCode.SByte: case PrimitiveTypeCode.Int16: case PrimitiveTypeCode.UInt16: case PrimitiveTypeCode.Int32: case PrimitiveTypeCode.Byte: case PrimitiveTypeCode.UInt32: case PrimitiveTypeCode.Int64: case PrimitiveTypeCode.UInt64: return true; default: return false; } } public static ParseResult Int32TryParse(char[] chars, int start, int length, out int value) { value = 0; if (length == 0) return ParseResult.Invalid; bool flag = chars[start] == '-'; if (flag) { if (length == 1) return ParseResult.Invalid; start++; length--; } int num = start + length; if (length > 10 || (length == 10 && chars[start] - 48 > 2)) { for (int i = start; i < num; i++) { int num2 = chars[i] - 48; if (num2 < 0 || num2 > 9) return ParseResult.Invalid; } return ParseResult.Overflow; } for (int j = start; j < num; j++) { int num3 = chars[j] - 48; if (num3 < 0 || num3 > 9) return ParseResult.Invalid; int num4 = 10 * value - num3; if (num4 > value) { for (j++; j < num; j++) { num3 = chars[j] - 48; if (num3 < 0 || num3 > 9) return ParseResult.Invalid; } return ParseResult.Overflow; } value = num4; } if (!flag) { if (value == -2147483648) return ParseResult.Overflow; value = -value; } return ParseResult.Success; } public static ParseResult Int64TryParse(char[] chars, int start, int length, out long value) { value = 0; if (length == 0) return ParseResult.Invalid; bool flag = chars[start] == '-'; if (flag) { if (length == 1) return ParseResult.Invalid; start++; length--; } int num = start + length; if (length > 19) { for (int i = start; i < num; i++) { int num2 = chars[i] - 48; if (num2 < 0 || num2 > 9) return ParseResult.Invalid; } return ParseResult.Overflow; } for (int j = start; j < num; j++) { int num3 = chars[j] - 48; if (num3 < 0 || num3 > 9) return ParseResult.Invalid; long num4 = 10 * value - num3; if (num4 > value) { for (j++; j < num; j++) { num3 = chars[j] - 48; if (num3 < 0 || num3 > 9) return ParseResult.Invalid; } return ParseResult.Overflow; } value = num4; } if (!flag) { if (value == -9223372036854775808) return ParseResult.Overflow; value = -value; } return ParseResult.Success; } public static ParseResult DecimalTryParse(char[] chars, int start, int length, out decimal value) { value = default(decimal); if (length == 0) return ParseResult.Invalid; bool flag = chars[start] == '-'; if (flag) { if (length == 1) return ParseResult.Invalid; start++; length--; } int i = start; int num = start + length; int num2 = num; int num3 = num; int num4 = 0; ulong num5 = 0; ulong num6 = 0; int num7 = 0; int num8 = 0; bool? nullable = null; bool? nullable2 = null; for (; i < num; i++) { char c = chars[i]; if (c == '.') goto IL_0074; if (c == 'E' || c == 'e') goto IL_0091; if (c < '0' || c > '9') return ParseResult.Invalid; if (i == start && c == '0') { i++; if (i != num) { switch (chars[i]) { case '.': break; case 'E': case 'e': goto IL_0091; default: return ParseResult.Invalid; } goto IL_0074; } } if (num7 < 29) { if (num7 == 28) { bool? nullable3 = nullable2; int valueOrDefault; if (!nullable3.HasValue) { nullable2 = (num5 > 7922816251426433759 || (num5 == 7922816251426433759 && (num6 > 354395033 || (num6 == 354395033 && c > '5')))); bool? nullable4 = nullable2; valueOrDefault = (nullable4.GetValueOrDefault() ? 1 : 0); } else valueOrDefault = (nullable3.GetValueOrDefault() ? 1 : 0); if (valueOrDefault != 0) goto IL_01ff; } if (num7 < 19) num5 = (ulong)((long)(num5 * 10) + (long)(c - 48)); else num6 = (ulong)((long)(num6 * 10) + (long)(c - 48)); num7++; continue; } goto IL_01ff; IL_0091: if (i == start) return ParseResult.Invalid; if (i == num2) return ParseResult.Invalid; i++; if (i == num) return ParseResult.Invalid; if (num2 < num) num3 = i - 1; c = chars[i]; bool flag2 = false; switch (c) { case '-': flag2 = true; i++; break; case '+': i++; break; } for (; i < num; i++) { c = chars[i]; if (c < '0' || c > '9') return ParseResult.Invalid; int num9 = 10 * num4 + (c - 48); if (num4 < num9) num4 = num9; } if (flag2) num4 = -num4; continue; IL_01ff: if (!nullable.HasValue) nullable = (c >= '5'); num8++; continue; IL_0074: if (i == start) return ParseResult.Invalid; if (i + 1 == num) return ParseResult.Invalid; if (num2 != num) return ParseResult.Invalid; num2 = i + 1; } num4 += num8; num4 -= num3 - num2; if (num7 <= 19) value = num5; else value = (decimal)num5 / new decimal(1, 0, 0, false, (byte)(num7 - 19)) + (decimal)num6; if (num4 > 0) { num7 += num4; if (num7 > 29) return ParseResult.Overflow; if (num7 != 29) value /= new decimal(1, 0, 0, false, (byte)num4); else { if (num4 > 1) { value /= new decimal(1, 0, 0, false, (byte)(num4 - 1)); if (value > 7922816251426433759354395033) return ParseResult.Overflow; } value *= 10; } } else { if (nullable == true && num4 >= -28) ++value; if (num4 < 0) { if (num7 + num4 + 28 <= 0) { value = (flag ? decimal.Zero : decimal.Zero); return ParseResult.Success; } if (num4 < -28) { value /= 10000000000000000000000000000; value *= new decimal(1, 0, 0, false, (byte)(-num4 - 28)); } else value *= new decimal(1, 0, 0, false, (byte)(-num4)); } } if (flag) value = -value; return ParseResult.Success; } public static bool TryConvertGuid(string s, out Guid g) { return Guid.TryParseExact(s, "D", out g); } public static bool TryHexTextToInt(char[] text, int start, int end, out int value) { value = 0; for (int i = start; i < end; i++) { char c = text[i]; int num; if (c <= '9' && c >= '0') num = c - 48; else if (c <= 'F' && c >= 'A') { num = c - 55; } else { if (c > 'f' || c < 'a') { value = 0; return false; } num = c - 87; } value += num << (end - 1 - i) * 4; } return true; } } }