控制面板设置小数点和数字分组符合后容易引起的bug

先了解一下通过CultureInfo.CurrentUICulture和CultureInfo.InvariantCulture与控制面板设置的关系
控制面板设置如图
这里写图片描述

   public partial class Form1 : Form
    {
        public Form1()
        {
            System.Globalization.CultureInfo cuf1 = CultureInfo.Currentulture;//资源管理器使用的当前区域性以便在运行时查找区域性特定的资源
            System.Globalization.CultureInfo cuf2 = CultureInfo.InvariantCulture;//不依赖于区域性(固定)的对象。
            List<CultureInfo> listCuf = new List<CultureInfo>() {cuf1, cuf2 };

            string str = string.Empty; 
            foreach (var c in listCuf)
            {
                str += c.TextInfo.ListSeparator+" "+ c.NumberFormat.NumberDecimalSeparator+" "+ c.NumberFormat.NumberGroupSeparator+" ";
                // str 为 | , 。 , . ,    可以看到 CurrentUICulture是获取的控制面板的设置,  InvariantCulture  则是自己默认的                    
            }
            ///ListSeparator属性是有set的,但是如果执行cuf1.TextInfo.ListSeparator = "?"  给ListSeparator赋值,会抛异常:实例为只读
            ///  其实反编译找到下面的方法 可以看到 能不能赋值是有条件的,不满足条件就抛出异常
            /// private void VerifyWritable()
            /// {
            ///     if (this.m_isReadOnly)
            ///     {
            ///         throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
            ///      }
            ///  }
            ///   这种new的CultureInfo对象就可以给ListSeparator属性赋值,原因也是在反编译里可以看到
            ///   NumberFormatInfo nfi = new CultureInfo("en-US", false).NumberFormat
            ///   nfi.TextInfo.ListSeparator = " ?";
        }
    }

下面是可能抛异常的情况.

//一般大家都是ToString(),其实等同于ToString(CultureInfo.CurrentCulture),ToDouble同理
double d1 = 3.3; //首先明确 ASP.NET里数值类型还是“.”表示的小数点,CultureInfo里NumberDecimalSeparator是体现在字符串上

string s1 = d1.ToString(CultureInfo.CurrentCulture); //s1=3!3  控制面板设置的是 "!" 为小数点 ,所以这里字符串为3!3
string s2= d1.ToString(CultureInfo.InvariantCulture);//s1=3.3   CultureInfo.InvariantCulture 是 "." 表示小数点,所以字符串是3.3

double d2 = Convert.ToDouble(s1, CultureInfo.CurrentCulture);//d2=3.3  CultureInfo.CurrentCulture能识别 "!" 所以成功转为3.3
double d3 = Convert.ToDouble(s1, CultureInfo.InvariantCulture);//// 抛异常: 输入字符串的格式不正确 CultureInfo.InvariantCulture里没有"!",识别不了

double d4 = Convert.ToDouble(s2,CultureInfo.CurrentCulture);//抛异常: 输入字符串的格式不正确。 CultureInfo.InvariantCulture里没有"!",识别不了
double d5 = Convert.ToDouble(s2,CultureInfo.InvariantCulture);//d5=3.3 CultureInfo.InvariantCulture能识别"." 所以成功转为3.3

//可以看出s1由d1 ToString时参数为CultureInfo.CurrentCulture , ToDouble时必须要 CultureInfo.CurrentCulture,s2同理
//所以如果转为string还是转回double ,ToString()和ToDoubl()的参数须保持一致,不然会抛异常   
//只是一般情况控制面板设置的恰好与  CultureInfo.InvariantCulture时一致的,所以没有抛出异常           

下面是数值可能不正确的情况

double d1 = 3.3; 
string s1 = d1.ToString(CultureInfo.CurrentCulture); //s1=3,3

double d3 = Convert.ToDouble(s1, CultureInfo.InvariantCulture);//d3=33 ,因为","在InvariantCulture是数字分组符号,数字分组符合只是为了方便肉眼看出数的位数或者大小,并不影响数值大小,所以这里会转化成33

最后举一个例子


  //假如有需求是一个数由整数位和小数位拼接而来,而我们的习惯肯定是用"."拼接.
   int a = 10;
   int b = 26;
   double c= Convert.ToDouble(a + "." + b);    
   //控制面板里没有"." 会抛异常. 将数字分组符号设为"." c=1026 都会有问题

所以建议中间过程ToString()和ToDoubl()时都用上CultureInfo.InvariantCulture参数来避免用户更改控制面板设置而引发bug,最后要显示到控件上用CultureInfo.CurrentCulture。

猜你喜欢

转载自blog.csdn.net/m0_38110784/article/details/80340569