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

ConvertUtils

static class ConvertUtils
using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data.SqlTypes; using System.Globalization; using System.Numerics; using System.Reflection; namespace Newtonsoft.Json.Utilities { internal static class ConvertUtils { internal struct TypeConvertKey : IEquatable<TypeConvertKey> { private readonly Type _initialType; private readonly Type _targetType; public Type InitialType => _initialType; public Type TargetType => _targetType; 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; } } 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 List<TypeInformation> PrimitiveTypeCodes = new List<TypeInformation> { 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) { if (TypeCodeMap.TryGetValue(t, out PrimitiveTypeCode value)) return value; if (t.IsEnum()) 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)); return GetTypeCode(t2); } } return PrimitiveTypeCode.Object; } public static PrimitiveTypeCode GetTypeCode(object o) { return GetTypeCode(o.GetType()); } 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 method = t.TargetType.GetMethod("op_Implicit", new Type[1] { t.InitialType }); if (method == (MethodInfo)null) method = t.TargetType.GetMethod("op_Explicit", new Type[1] { t.InitialType }); if (method == (MethodInfo)null) return null; MethodCall<object, object> call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(method); return (object o) => call(null, o); } internal static BigInteger ToBigInteger(object value) { if (value is BigInteger) return (BigInteger)value; if (value is string) return BigInteger.Parse((string)value, CultureInfo.InvariantCulture); if (value is float) return new BigInteger((float)value); if (value is double) return new BigInteger((double)value); if (value is decimal) return new BigInteger((decimal)value); if (value is int) return new BigInteger((int)value); if (value is long) return new BigInteger((long)value); if (value is uint) return new BigInteger((uint)value); if (value is ulong) return new BigInteger((ulong)value); if (value is byte[]) return new BigInteger((byte[])value); 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))) 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 (ulong)i; } public static object Convert(object initialValue, CultureInfo culture, Type targetType) { if (initialValue == null) throw new ArgumentNullException("initialValue"); if (ReflectionUtils.IsNullableType(targetType)) targetType = Nullable.GetUnderlyingType(targetType); Type type = initialValue.GetType(); if (targetType == type) return initialValue; if (IsConvertible(initialValue.GetType()) && IsConvertible(targetType)) { if (targetType.IsEnum()) { if (initialValue is string) return Enum.Parse(targetType, initialValue.ToString(), true); if (IsInteger(initialValue)) return Enum.ToObject(targetType, initialValue); } return System.Convert.ChangeType(initialValue, targetType, culture); } if (initialValue is DateTime && targetType == typeof(DateTimeOffset)) return new DateTimeOffset((DateTime)initialValue); if (initialValue is byte[] && targetType == typeof(Guid)) return new Guid((byte[])initialValue); if (initialValue is string) { if (targetType == typeof(Guid)) return new Guid((string)initialValue); if (targetType == typeof(Uri)) return new Uri((string)initialValue, UriKind.RelativeOrAbsolute); if (targetType == typeof(TimeSpan)) return ParseTimeSpan((string)initialValue); if (targetType == typeof(byte[])) return System.Convert.FromBase64String((string)initialValue); if (typeof(Type).IsAssignableFrom(targetType)) return Type.GetType((string)initialValue, true); } if (targetType == typeof(BigInteger)) return ToBigInteger(initialValue); if (initialValue is BigInteger) return FromBigInteger((BigInteger)initialValue, targetType); TypeConverter converter = GetConverter(type); if (converter != null && converter.CanConvertTo(targetType)) return converter.ConvertTo(null, culture, initialValue, targetType); TypeConverter converter2 = GetConverter(targetType); if (converter2 != null && converter2.CanConvertFrom(type)) return converter2.ConvertFrom(null, culture, initialValue); if (initialValue == DBNull.Value) { if (ReflectionUtils.IsNullable(targetType)) return EnsureTypeAssignable(null, type, targetType); throw new Exception("Can not convert null {0} into non-nullable {1}.".FormatWith(CultureInfo.InvariantCulture, type, targetType)); } if (initialValue is INullable) return EnsureTypeAssignable(ToValue((INullable)initialValue), type, targetType); if (targetType.IsInterface() || targetType.IsGenericTypeDefinition() || targetType.IsAbstract()) throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), "targetType"); throw new InvalidOperationException("Can not convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, type, targetType)); } public static bool TryConvert(object initialValue, CultureInfo culture, Type targetType, out object convertedValue) { try { convertedValue = Convert(initialValue, culture, targetType); return true; } catch { convertedValue = null; return false; } } 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 convertedValue)) return convertedValue; 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 != (Type)null) ? initialType.ToString() : "{null}", targetType)); } public static object ToValue(INullable nullableValue) { if (nullableValue == null) return null; if (nullableValue is SqlInt32) return ToValue((SqlInt32)nullableValue); if (nullableValue is SqlInt64) return ToValue((SqlInt64)nullableValue); if (nullableValue is SqlBoolean) return ToValue((SqlBoolean)nullableValue); if (nullableValue is SqlString) return ToValue((SqlString)nullableValue); if (nullableValue is SqlDateTime) return ToValue((SqlDateTime)nullableValue); throw new ArgumentException("Unsupported INullable type: {0}".FormatWith(CultureInfo.InvariantCulture, nullableValue.GetType())); } internal static TypeConverter GetConverter(Type t) { return JsonTypeReflector.GetTypeConverter(t); } public static bool IsInteger(object value) { switch (GetTypeCode(value)) { 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; for (int i = start; i < num; i++) { int num2 = chars[i] - 48; if (num2 < 0 || num2 > 9) return ParseResult.Invalid; int num3 = 10 * value - num2; if (num3 > value) { for (i++; i < num; i++) { num2 = chars[i] - 48; if (num2 < 0 || num2 > 9) return ParseResult.Invalid; } return ParseResult.Overflow; } value = num3; } 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; for (int i = start; i < num; i++) { int num2 = chars[i] - 48; if (num2 < 0 || num2 > 9) return ParseResult.Invalid; long num3 = 10 * value - num2; if (num3 > value) { for (i++; i < num; i++) { num2 = chars[i] - 48; if (num2 < 0 || num2 > 9) return ParseResult.Invalid; } return ParseResult.Overflow; } value = num3; } if (!flag) { if (value == -9223372036854775808) return ParseResult.Overflow; value = -value; } return ParseResult.Success; } } }