Clever C# Value Type and Character Converter | JSON Serialization and Deserialization

2021年11月3日 46点热度 0人点赞 1条评论
内容目录
    /// <summary>
    /// Convert between value types and strings
    /// </summary>
    public class JsonStringToNumberConverter : JsonConverterFactory
    {
        /// <summary>
        /// Gets the default instance
        /// </summary>
        public static JsonStringToNumberConverter Default { get; } = new JsonStringToNumberConverter();

        /// <summary>
        /// Determines whether the type can be converted
        /// </summary>
        /// <param name="typeToConvert"></param>
        /// <returns></returns>
        public override bool CanConvert(Type typeToConvert)
        {
            var typeCode = Type.GetTypeCode(typeToConvert);
            return typeCode == TypeCode.Int32 ||
                typeCode == TypeCode.Decimal ||
                typeCode == TypeCode.Double ||
                typeCode == TypeCode.Single ||
                typeCode == TypeCode.Int64 ||
                typeCode == TypeCode.Int16 ||
                typeCode == TypeCode.Byte ||
                typeCode == TypeCode.UInt32 ||
                typeCode == TypeCode.UInt64 ||
                typeCode == TypeCode.UInt16 ||
                typeCode == TypeCode.SByte;
        }

        /// <summary>
        /// Creates a converter
        /// </summary>
        /// <param name="typeToConvert"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
        {
            var type = typeof(StringNumberConverter<>).MakeGenericType(typeToConvert);
            var converter = Activator.CreateInstance(type);
            if (converter == null)
            {
                throw new InvalidOperationException($"Cannot create converter for type {type.Name}");
            }
            return (JsonConverter)converter;
        }

        /// <summary>
        /// Converter for textual representation of numbers
        /// </summary>
        /// <typeparam name="T"></typeparam>
        private class StringNumberConverter<T> : JsonConverter<T>
        {
            private static readonly TypeCode typeCode = Type.GetTypeCode(typeof(T));

            /// <summary>
            /// Read
            /// </summary>
            /// <param name="reader"></param>
            /// <param name="typeToConvert"></param>
            /// <param name="options"></param>
            /// <returns></returns>
            public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {
                switch (reader.TokenType)
                {
                    case JsonTokenType.Number:
                        if (typeCode == TypeCode.Int32)
                        {
                            if (reader.TryGetInt32(out var value))
                            {
                                return Unsafe.As<int, T>(ref value);
                            }
                        }
                        if (typeCode == TypeCode.Int64)
                        {
                            if (reader.TryGetInt64(out var value))
                            {
                                return Unsafe.As<long, T>(ref value);
                            }
                        }
                        if (typeCode == TypeCode.Decimal)
                        {
                            if (reader.TryGetDecimal(out var value))
                            {
                                return Unsafe.As<decimal, T>(ref value);
                            }
                        }
                        if (typeCode == TypeCode.Double)
                        {
                            if (reader.TryGetDouble(out var value))
                            {
                                return Unsafe.As<double, T>(ref value);
                            }
                        }
                        if (typeCode == TypeCode.Single)
                        {
                            if (reader.TryGetSingle(out var value))
                            {
                                return Unsafe.As<float, T>(ref value);
                            }
                        }
                        if (typeCode == TypeCode.Byte)
                        {
                            if (reader.TryGetByte(out var value))
                            {
                                return Unsafe.As<byte, T>(ref value);
                            }
                        }
                        if (typeCode == TypeCode.SByte)
                        {
                            if (reader.TryGetSByte(out var value))
                            {
                                return Unsafe.As<sbyte, T>(ref value);
                            }
                        }
                        if (typeCode == TypeCode.Int16)
                        {
                            if (reader.TryGetInt16(out var value))
                            {
                                return Unsafe.As<short, T>(ref value);
                            }
                        }
                        if (typeCode == TypeCode.UInt16)
                        {
                            if (reader.TryGetUInt16(out var value))
                            {
                                return Unsafe.As<ushort, T>(ref value);
                            }
                        }
                        if (typeCode == TypeCode.UInt32)
                        {
                            if (reader.TryGetUInt32(out var value))
                            {
                                return Unsafe.As<uint, T>(ref value);
                            }
                        }
                        if (typeCode == TypeCode.UInt64)
                        {
                            if (reader.TryGetUInt64(out var value))
                            {
                                return Unsafe.As<ulong, T>(ref value);
                            }
                        }
                        break;

                    case JsonTokenType.String:
                        IConvertible str = reader.GetString() ?? "";
                        return (T)str.ToType(typeof(T), null);

                }

                throw new NotSupportedException($"Cannot convert {reader.TokenType} to {typeToConvert}");
            }

            /// <summary>
            /// Write
            /// </summary>
            /// <param name="writer"></param>
            /// <param name="value"></param>
            /// <param name="options"></param>
            public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
            {
                switch (typeCode)
                {
                    case TypeCode.Int32:
                        writer.WriteNumberValue(Unsafe.As<T, int>(ref value));
                        break;
                    case TypeCode.UInt32:
                        writer.WriteNumberValue(Unsafe.As<T, uint>(ref value));
                        break;
                    case TypeCode.Decimal:
                        writer.WriteNumberValue(Unsafe.As<T, decimal>(ref value));
                        break;
                    case TypeCode.Double:
                        writer.WriteNumberValue(Unsafe.As<T, double>(ref value));
                        break;
                    case TypeCode.Single:
                        writer.WriteNumberValue(Unsafe.As<T, uint>(ref value));
                        break;
                    case TypeCode.UInt64:
                        writer.WriteNumberValue(Unsafe.As<T, ulong>(ref value));
                        break;
                    case TypeCode.Int64:
                        writer.WriteNumberValue(Unsafe.As<T, long>(ref value));
                        break;
                    case TypeCode.Int16:
                        writer.WriteNumberValue(Unsafe.As<T, short>(ref value));
                        break;
                    case TypeCode.UInt16:
                        writer.WriteNumberValue(Unsafe.As<T, ushort>(ref value));
                        break;
                    case TypeCode.Byte:
                        writer.WriteNumberValue(Unsafe.As<T, byte>(ref value));
                        break;
                    case TypeCode.SByte:
                        writer.WriteNumberValue(Unsafe.As<T, sbyte>(ref value));
                        break;
                    default:
                        throw new NotSupportedException($"Unsupported non-numeric type {typeof(T)}");
                }
            }
        }
    }

痴者工良

高级程序员劝退师

文章评论