面向云技术架构 - 痴者工良

  • 首页
  • 工良写的电子书
    • kubernetes 教程
    • 从 C# 入门 Kafka
    • 多线程和异步
    • 动态编程-反射、特性、AOP
    • 表达式树
  • 本站文章导航
  • 隐私政策
愿有人陪你颠沛流离
遇到能让你付出的事物或者人,都是一种运气。
能遇到,就该珍惜。或许你们最终没能在一起,但你会切实地感受到力量。
正因为这样,那段相遇才变得有价值,才没有辜负这世间的每一段相遇。
  1. 首页
  2. .NET
  3. 正文

巧妙的 C# 值类型与字符转换器

2021年11月3日 902点热度 0人点赞 1条评论
内容纲要

其代码如下:

    /// <summary>
    /// 值类型和字符串互转
    /// </summary>
    public class JsonStringToNumberConverter : JsonConverterFactory
    {
        /// <summary>
        /// 获取默认实例
        /// </summary>
        public static JsonStringToNumberConverter Default { get; } = new JsonStringToNumberConverter();

        /// <summary>
        /// 返回类型是否可以转换
        /// </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>
        /// 创建转换器
        /// </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($"无法创建 {type.Name} 类型的转换器");
            }
            return (JsonConverter)converter;
        }

        /// <summary>
        /// 文本表示的数值转换器
        /// </summary>
        /// <typeparam name="T"></typeparam>
        private class StringNumberConverter<T> : JsonConverter<T>
        {
            private static readonly TypeCode typeCode = Type.GetTypeCode(typeof(T));

            /// <summary>
            /// 读取
            /// </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($"无法将{reader.TokenType}转换为{typeToConvert}");
            }

            /// <summary>
            /// 写入
            /// </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($"不支持非数字类型{typeof(T)}");
                }
            }
        }
    }
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: c 字符 巧妙 类型 转换器
最后更新:2022年1月17日

痴者工良

高级程序员劝退师

点赞
< 上一篇
下一篇 >

文章评论

  • 痴者工良

    可以使用 TypeDescriptor、TypeConverter 来做
    return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(obj.ToString());

    2022年6月24日
    回复
  • razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    取消回复

    COPYRIGHT © 2022 whuanle.cn. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang

    粤ICP备18051778号

    粤公网安备 44030902003257号