System.Double

C# Double 结构体详解
本文详细介绍了 C# 中 Double 结构体的功能与实现,包括常量定义、比较操作、转换方法等,并提供了丰富的示例代码来展示如何使用这些功能。
using System.Runtime.InteropServices;
using System.Globalization;
namespace System
{
    [StructLayout(LayoutKind.Sequential), Serializable,ComVisible(true)]
    public struct Double : System.IComparable, System.IFormattable, System.IConvertible, System.IComparable<double>, System.IEquatable<double>
    {        
        public const double MinValue = -1.7976931348623157e+308;
        public const double MaxValue = 1.7976931348623157e+308;
        public const double Epsilon = 4.9406564584124654e-324;
        public const double NegativeInfinity = System.BitConverter.ToDouble(System.BitConverter.GetBytes(0xFFF0000000000000),0);
        public const double PositiveInfinity = System.BitConverter.ToDouble(System.BitConverter.GetBytes(0x7FF0000000000000),0);
        public const double NaN = System.BitConverter.ToDouble(System.BitConverter.GetBytes(0xFFF8000000000000),0);
        internal double m_value;
        static internal double NegativeZero;
        public static bool IsInfinity(double d)
        {
            //.maxstack  8
            //IL_0000:  ldarga.s   d
            //IL_0002:  conv.u
            //IL_0003:  ldind.i8
            //IL_0004:  ldc.i8     0x7fffffffffffffff
            //IL_000d:  and
            //IL_000e:  ldc.i8     0x7ff0000000000000
            //IL_0017:  ceq
            //IL_0019:  ret
            return *((long*)&d)& 0x7fffffffffffffff ==0x7ff0000000000000;
        }
        public static bool IsPositiveInfinity(double d)
        {
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldc.r8     (00 00 00 00 00 00 F0 7F)
            //IL_000a:  bne.un.s   IL_000e
            //IL_000c:  ldc.i4.1
            //IL_000d:  ret
            //IL_000e:  ldc.i4.0
            //IL_000f:  ret
            if (d != float.PositiveInfinity)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        public static bool IsNegativeInfinity(double d)
        {
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldc.r8     (00 00 00 00 00 00 F0 FF)
            //IL_000a:  bne.un.s   IL_000e
            //IL_000c:  ldc.i4.1
            //IL_000d:  ret
            //IL_000e:  ldc.i4.0
            //IL_000f:  ret
            if (d != float.NegativeInfinity)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        internal static bool IsNegative(double d)
        {
            //.maxstack  8
            //IL_0000:  ldarga.s   d
            //IL_0002:  conv.u
            //IL_0003:  ldind.i8
            //IL_0004:  ldc.i8     0x8000000000000000
            //IL_000d:  and
            //IL_000e:  ldc.i8     0x8000000000000000
            //IL_0017:  ceq
            //IL_0019:  ret
            return (*((ulong*)&d) & 0x8000000000000000) == 0x8000000000000000;
        }
        [System.Runtime.ConstrainedExecution.ReliabilityContractAttribute(System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState, System.Runtime.ConstrainedExecution.Cer.Success)]
        public static bool IsNaN(double d)
        {            
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldarg.0
            //IL_0002:  beq.s      IL_0006
            //IL_0004:  ldc.i4.1
            //IL_0005:  ret
            //IL_0006:  ldc.i4.0
            //IL_0007:  ret
            if (d == d)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        public new virtual sealed int CompareTo(object @value)
        {
            //.maxstack  2
            //.locals init (float64 V_0)
            //IL_0000:  ldarg.1
            //IL_0001:  brtrue.s   IL_0005
            //IL_0003:  ldc.i4.1
            //IL_0004:  ret
            //IL_0005:  ldarg.1
            //IL_0006:  isinst     System.Double
            //IL_000b:  brfalse.s  IL_0040
            //IL_000d:  ldarg.1
            //IL_000e:  unbox.any  System.Double
            //IL_0013:  stloc.0
            //IL_0014:  ldarg.0
            //IL_0015:  ldind.r8
            //IL_0016:  ldloc.0
            //IL_0017:  bge.un.s   IL_001b
            //IL_0019:  ldc.i4.m1
            //IL_001a:  ret
            //IL_001b:  ldarg.0
            //IL_001c:  ldind.r8
            //IL_001d:  ldloc.0
            //IL_001e:  ble.un.s   IL_0022
            //IL_0020:  ldc.i4.1
            //IL_0021:  ret
            //IL_0022:  ldarg.0
            //IL_0023:  ldind.r8
            //IL_0024:  ldloc.0
            //IL_0025:  bne.un.s   IL_0029
            //IL_0027:  ldc.i4.0
            //IL_0028:  ret
            //IL_0029:  ldarg.0
            //IL_002a:  ldind.r8
            //IL_002b:  call       bool System.Double::IsNaN(float64)
            //IL_0030:  brfalse.s  IL_003e
            //IL_0032:  ldloc.0
            //IL_0033:  call       bool System.Double::IsNaN(float64)
            //IL_0038:  brtrue.s   IL_003c
            //IL_003a:  ldc.i4.m1
            //IL_003b:  ret
            //IL_003c:  ldc.i4.0
            //IL_003d:  ret
            //IL_003e:  ldc.i4.1
            //IL_003f:  ret
            //IL_0040:  ldstr      "Arg_MustBeDouble"
            //IL_0045:  call       string System.Environment::GetResourceString(string)
            //IL_004a:  newobj     instance void System.ArgumentException::.ctor(string)
            //IL_004f:  throw

            double V_0;
            if (@value == null)
            {
                return 1;
            }
            else
            {
                if (@value as double == null)
                {
                    //IL_0040
                    throw new System.ArgumentException(System.Environment.GetResourceString("Arg_MustBeDouble"));
                }
                else
                {
                    //IL_000d
                    V_0 = (double)@value;
                    if (this >= V_0)
                    {
                        if (this <= V_0)
                        {
                            //IL_0022
                            if (this != V_0)
                            {
                                //IL_0029
                                if (double.IsNaN(this))
                                {
                                    if (double.IsNaN(V_0))
                                    {
                                        return 0;
                                    }
                                    else
                                    {
                                        return -1;
                                    }
                                }
                                else
                                {
                                    return 1;
                                }
                            }
                            else
                            {
                                return 0;
                            }
                        }
                        else
                        {
                            return 1;
                        }
                    }
                    else
                    {
                        return -1;
                    }
                }
            }

        }
        public new virtual sealed int CompareTo(double @value)
        {
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  ldarg.1
            //IL_0003:  bge.un.s   IL_0007
            //IL_0005:  ldc.i4.m1
            //IL_0006:  ret
            //IL_0007:  ldarg.0
            //IL_0008:  ldind.r8
            //IL_0009:  ldarg.1
            //IL_000a:  ble.un.s   IL_000e
            //IL_000c:  ldc.i4.1
            //IL_000d:  ret
            //IL_000e:  ldarg.0
            //IL_000f:  ldid.r8
            //IL_0010:  ldarg.1
            //IL_0011:  bne.un.s   IL_0015
            //IL_0013:  ldc.i4.0
            //IL_0014:  ret
            //IL_0015:  ldarg.0
            //IL_0016:  ldind.r8
            //IL_0017:  call       bool System.Double::IsNaN(float64)
            //IL_001c:  brfalse.s  IL_002a
            //IL_001e:  ldarg.1
            //IL_001f:  call       bool System.Double::IsNaN(float64)
            //IL_0024:  brtrue.s   IL_0028
            //IL_0026:  ldc.i4.m1
            //IL_0027:  ret
            //IL_0028:  ldc.i4.0
            //IL_0029:  ret
            //IL_002a:  ldc.i4.1
            //IL_002b:  ret
            if (this >= @value)
            {
                if (this <= @value)
                {
                    if (this != @value)
                    {
                        //IL_0015 
                        if (double.IsNaN(this))
                        {
                            if (double.IsNaN(@value))
                            {
                                return 0;
                            }
                            else
                            {
                                return -1;
                            }
                        }
                        else
                        {
                            return 1;
                        }
                    }
                    else
                    {
                        return 0;
                    }
                }
                else
                {
                    return 1;
                }
            }
            else
            {
                return -1;
            }
        }
        public virtual bool Equals(object obj)
        {
            //.maxstack  2
            //.locals init (float64 V_0)
            //IL_0000:  ldarg.1
            //IL_0001:  isinst     System.Double
            //IL_0006:  brtrue.s   IL_000a
            //IL_0008:  ldc.i4.0
            //IL_0009:  ret
            //IL_000a:  ldarg.1
            //IL_000b:  unbox.any  System.Double
            //IL_0010:  stloc.0
            //IL_0011:  ldloc.0
            //IL_0012:  ldarg.0
            //IL_0013:  ldind.r8
            //IL_0014:  bne.un.s   IL_0018
            //IL_0016:  ldc.i4.1
            //IL_0017:  ret
            //IL_0018:  ldloc.0
            //IL_0019:  call       bool System.Double::IsNaN(float64)
            //IL_001e:  brfalse.s  IL_0028
            //IL_0020:  ldarg.0
            //IL_0021:  ldind.r8
            //IL_0022:  call       bool System.Double::IsNaN(float64)
            //IL_0027:  ret
            //IL_0028:  ldc.i4.0
            //IL_0029:  ret
            double V_0;
            if (obj as double == null)
            {
                return false;
            }
            else
            {
                V_0 = (double)obj;
                if (V_0 != this)
                {
                    if (double.IsNaN(V_0))
                    {
                        return double.IsNaN(this);
                    }
                    else
                    {
                        return false;
                    }
                }
                else { return true; }
            }

        }
        public new virtual sealed bool Equals(double obj)
        {
            //.maxstack  8
            //IL_0000:  ldarg.1
            //IL_0001:  ldarg.0
            //IL_0002:  ldind.r8
            //IL_0003:  bne.un.s   IL_0007
            //IL_0005:  ldc.i4.1
            //IL_0006:  ret
            //IL_0007:  ldarg.1
            //IL_0008:  call       bool System.Double::IsNaN(float64)
            //IL_000d:  brfalse.s  IL_0017
            //IL_000f:  ldarg.0
            //IL_0010:  ldind.r8
            //IL_0011:  call       bool System.Double::IsNaN(float64)
            //IL_0016:  ret
            //IL_0017:  ldc.i4.0
            //IL_0018:  ret
            if (obj != this)
            {
                if (ouble.IsNaN(obj))
                {
                    return double.IsNaN(this);
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return true;
            }

        }
        public virtual int GetHashCode()
        {
            //.maxstack  3
            //.locals init (float64 V_0,
            //int64 V_1)
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  stloc.0
            //IL_0003:  ldloc.0
            //IL_0004:  ldc.r8     0.0
            //IL_000d:  bne.un.s   IL_0011
            //IL_000f:  ldc.i4.0
            //IL_0010:  ret
            //IL_0011:  ldloca.s   V_0
            //IL_0013:  conv.u
            //IL_0014:  ldind.i8
            //IL_0015:  stloc.1
            //IL_0016:  ldloc.1
            //IL_0017:  conv.i4
            //IL_0018:  ldloc.1
            //IL_0019:  ldc.i4.s   32
            //IL_001b:  shr
            //IL_001c:  conv.i4
            //IL_001d:  xor
            //IL_001e:  ret
            double V_0; 
            long V_1;
            V_0 = this;
            if (V_0 != 0.0d) 
            {
                V_1=*((long*)&V_0);
                return (int)V_1 ^ (int)(V_1>>32);
            } 
            else 
            { 
                return 0; 
            }
        }
        public virtual string ToString()
        {
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  ldnull
            //IL_0003:  call       class System.Globalization.NumberFormatInfo System.Globalization.NumberFormatInfo::get_CurrentInfo()
            //IL_0008:  call       string System.Number::FormatDouble(float64,
            //string,
            //class System.Globalization.NumberFormatInfo)
            //IL_000d:  ret
            return System.Number.FormatDouble(this,null,NumberFormatInfo.CurrentInfo);
        }
        public string ToString(string format)
        {
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  ldarg.1
            //IL_0003:  call       class System.Globalization.NumberFormatInfo System.Globalization.NumberFormatInfo::get_CurrentInfo()
            //IL_0008:  call       string System.Number::FormatDouble(float64,
            //string,
            //class System.Globalization.NumberFormatInfo)
            //IL_000d:  ret
            return System.Number.FormatDouble(this, format, NumberFormatInfo.CurrentInfo);

        }
        public new virtual sealed string ToString(System.IFormatProvider provider)
        {
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  ldnull
            //IL_0003:  ldarg.1
            //IL_0004:  call       class System.Globalization.NumberFormatInfo System.Globalization.NumberFormatInfo::GetInstance(class System.IFormatProvider)
            //IL_0009:  call       string System.Number::FormatDouble(float64,
            //string,
            //class System.Globalization.NumberFormatInfo)
            //IL_000e:  ret
            return System.Number.FormatDouble(this, null, NumberFormatInfo.GetInstance(provider));
        }
        public new virtual sealed string ToString(string format, System.IFormatProvider provider)
        {
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  ldarg.1
            //IL_0003:  ldarg.2
            //IL_0004:  call       class System.Globalization.NumberFormatInfo System.Globalization.NumberFormatInfo::GetInstance(class System.IFormatProvider)
            //IL_0009:  call       string System.Number::FormatDouble(float64,
            //string,
            //class System.Globalization.NumberFormatInfo)
            //IL_000e:  ret
            return System.Number.FormatDouble(this, format, NumberFormatInfo.etInstance(provider));
        }
        public static double Parse(string s)
        {
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldc.i4     0xe7
            //IL_0006:  call       class System.Globalization.NumberFormatInfo System.Globalization.NumberFormatInfo::get_CurrentInfo()
            //IL_000b:  call       float64 System.Double::Parse(string,
            //valuetype System.Globalization.NumberStyles,
            //class System.Globalization.NumberFormatInfo)
            //IL_0010:  ret
            return System.Double.Parse(s, NumberStyles.AllowThousands | NumberStyles.Float,NumberFormatInfo.CurrentInfo);
        }
        public static double Parse(string s, System.Globalization.NumberStyles style)
        {
            //.maxstack  8
            //IL_0000:  ldarg.1
            //IL_0001:  call       void System.Globalization.NumberFormatInfo::ValidateParseStyleFloatingPoint(valuetype System.Globalization.NumberStyles)
            //IL_0006:  ldarg.0
            //IL_0007:  ldarg.1
            //IL_0008:  call       class System.Globalization.NumberFormatInfo System.Globalization.NumberFormatInfo::get_CurrentInfo()
            //IL_000d:  call       float64 System.Double::Parse(string,
            //valuetype System.Globalization.NumberStyles,
            //class System.Globalization.NumberFormatInfo)
            //IL_0012:  ret
            NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
            return System.Double.Parse(s, style, NumberFormatInfo.CurrentInfo);
        }
        public static double Parse(string s, System.IFormatProvider provider)
        {
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldc.i4     0xe7
            //IL_0006:  ldarg.1
            //IL_0007:  call       class System.Globalization.NumberFormatInfo System.Globalization.NumberFormatInfo::GetInstance(class System.IFormatProvider)
            //IL_000c:  call       float64 System.Double::Parse(string,
            //valuetype System.Globalization.NumberStyles,
            //class System.Globalization.NumberFormatInfo)
            //IL_0011:  ret
            return System.Double.Parse(s, NumberStyles.AllowThousands | NumberStyles.Float, NumberFormatInfo.GetInstance(provider));
        }
        public static double Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider)
        {
            //.maxstack  8
            //IL_0000:  ldarg.1
            //IL_0001:  call       void System.Globalization.NumberFormatInfo::ValidateParseStyleFloatingPoint(valuetype System.Globalization.NumberStyles)
            //IL_0006:  ldarg.0
            //IL_0007:  ldarg.1
            //IL_0008:  ldarg.2
            //IL_0009:  call       class System.Globalization.NumberFormatInfo System.Globalization.NumberFormatInfo::GetInstance(class System.IFormatProvider)
            //IL_000e:  call       float64 System.Double::Parse(string,
            //valuetype System.Globalization.NumberStyles,
            //class System.Globalization.NumberFormatInfo)
            //IL_0013:  ret
            NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
            return System.Double.Parse(s, style, NumberFormatInfo.GetInstance(provider));
        }
        private static double Parse(string s, System.Globalization.NumberStyles style, System.Globalization.NumberFormatInfo info)
        {
            //.maxstack  3
            //.locals init (string V_0,
            //float64 V_1)
            //.try
            //{
            //IL_0000:  ldarg.0
            //IL_0001:  ldarg.1
            //IL_0002:  ldarg.2
            //IL_0003:  call       float64 System.Number::ParseDouble(string,
            //valuetype System.Globalization.NumberStyles,
            //class System.Globalization.NumberFormatInfo)
            //IL_0008:  stloc.1
            //IL_0009:  leave.s    IL_0063
            //}
            //catch System.FormatException
            //{
            //IL_00b:  pop
            //IL_000c:  ldarg.0
            //IL_000d:  callvirt   instance string System.String::Trim()
            //IL_0012:  stloc.0
            //IL_0013:  ldloc.0
            //IL_0014:  ldarg.2
            //IL_0015:  callvirt   instance string System.Globalization.NumberFormatInfo::get_PositiveInfinitySymbol()
            //IL_001a:  callvirt   instance bool System.String::Equals(string)
            //IL_001f:  brfalse.s  IL_002d
            //IL_0021:  ldc.r8     (00 00 00 00 00 00 F0 7F)
            //IL_002a:  stloc.1
            //IL_002b:  leave.s    IL_0063
            //IL_002d:  ldloc.0
            //IL_002e:  ldarg.2
            //IL_002f:  callvirt   instance string System.Globalization.NumberFormatInfo::get_NegativeInfinitySymbol()
            //IL_0034:  callvirt   instance bool System.String::Equals(string)
            //IL_0039:  brfalse.s  IL_0047
            //IL_003b:  ldc.r8     (00 00 00 00 00 00 F0 FF)
            //IL_0044:  stloc.1
            //IL_0045:  leave.s    IL_0063
            //IL_0047:  ldloc.0
            //IL_0048:  ldarg.2
            //IL_0049:  callvirt   instance string System.Globalization.NumberFormatInfo::get_NaNSymbol()
            //IL_004e:  callvirt   instance bool System.String::Equals(string)
            //IL_0053:  brfalse.s  IL_0061
            //IL_0055:  ldc.r8     (00 00 00 00 00 00 F8 FF)
            //IL_005e:  stloc.1
            //IL_005f:  leave.s    IL_0063
            //IL_0061:  rethrow
            //}
            //IL_0063:  ldloc.1
            //IL_0064:  ret
            string V_0;
            double V_1;
            try
            {
                V_1 = System.Number.ParseDouble(s, style, info);
            }
            catch (System.FormatException)
            {
                //IL_000b: 
                V_0 = s.Trim();
                if (V_0.Equals(info.PositiveInfinitySymbol))
                {
                    V_1 = double.PositiveInfinity;
                }
                else
                {
                    //IL_0029
                    if (V_0.Equals(info.NegativeInfinitySymbol))
                    {
                        V_1 = double.NegativeInfinity;
                    }
                    else
                    {
                        if (V_0.Equals(info.NaNSymbol))
                        {
                            V_1 = double.NaN;
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
            }
            return V_1;
        }
        public static bool TryParse(string s, out double result)
        {
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldc.i4     0xe7
            //IL_0006:  call       class System.Globalization.NumberFormatInfo System.Globalization.NumberFormatInfo::get_CurrentInfo()
            //IL_000b:  ldarg.1
            //IL_000c:  call       bool System.Double::TryParse(string,
            //valuetype System.Globalization.NumberStyles,
            //class System.Globalization.NumberFormatInfo,
            //float64&)
            //IL_0011:  ret
            return System.Double.TryParse(s, NumberStyles.AllowThousands | NumberStyles.Float, NumberFormatInfo.CurrentInfo, out result);
        }
        public static bool TryParse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out double result)
        {
            //.maxstack  8
            //IL_0000:  ldarg.1
            //IL_0001:  call       void System.Globalization.NumberFormatInfo::ValidateParseStyleFloatingPoint(valuetype System.Globalization.NumberStyles)
            //IL_0006:  ldarg.0
            //IL_0007:  ldarg.1
            //IL_0008:  ldarg.2
            //IL_0009:  call       class System.Globalization.NumberFormatInfo System.Globalization.NumberFormatInfo::GetInstance(class System.IFormatProvider)
            //IL_000e:  larg.3
            //IL_000f:  call       bool System.Double::TryParse(string,
            //valuetype System.Globalization.NumberStyles,
            //class System.Globalization.NumberFormatInfo,
            //float64&)
            //IL_0014:  ret
            NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
            return System.Double.TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result);
        }
        private static bool TryParse(string s, System.Globalization.NumberStyles style, System.Globalization.NumberFormatInfo info, out double result)
        {
            //.maxstack  4
            //.locals init (bool V_0,
            //string V_1)
            //IL_0000:  ldarg.0
            //IL_0001:  brtrue.s   IL_0010
            //IL_0003:  ldarg.3
            //IL_0004:  ldc.r8     0.0
            //IL_000d:  stind.r8
            //IL_000e:  ldc.i4.0
            //IL_000f:  ret
            //IL_0010:  ldarg.0
            //IL_0011:  ldarg.1
            //IL_0012:  ldarg.2
            //IL_0013:  ldarg.3
            //IL_0014:  call       bool System.Number::TryParseDouble(string,
            //valuetype System.Globalization.NumberStyles,
            //class System.Globalization.NumberFormatInfo,
            //float64&)
            //IL_0019:  stloc.0
            //IL_001a:  ldloc.0
            //IL_001b:  brtrue.s   IL_0077
            //IL_001d:  ldarg.0
            //IL_001e:  callvirt   instance string System.String::Trim()
            //IL_0023:  stloc.1
            //IL_0024:  ldloc.1
            //IL_0025:  ldarg.2
            //IL_0026:  callvirt   instance string System.Globalization.NumberFormatInfo::get_PositiveInfinitySymbol()
            //IL_002b:  callvirt   instance bool System.String::Equals(string)
            //IL_0030:  brfalse.s  IL_003f
            //IL_0032:  ldarg.3
            //IL_0033:  ldc.r8     (00 00 00 00 00 00 F0 7F)
            //IL_003c:  stind.r8
            //IL_003d:  br.s       IL_0077
            //IL_003f:  ldloc.1
            //IL_0040:  ldarg.2
            //IL_0041:  callvirt   instance string System.Globalization.NumberFormatInfo::get_NegativeInfinitySymbol()
            //IL_0046:  callvirt   instance bool System.String::Equals(string)
            //IL_004b:  brfalse.s  IL_005a
            //IL_004d:  ldarg.3
            //IL_004e:  ldc.r8     (00 00 00 00 00 00 F0 FF)
            //IL_0057:  stind.r8
            //IL_0058:  br.s       IL_0077
            //IL_005a:  ldloc.1
            //IL_005b:  ldarg.2
            //IL_005c:  callvirt   instance string System.Globalization.NumberFormatInfo::get_NaNSymbol()
            //IL_0061:  callvirt   instance bool System.String::Equals(string)
            //IL_0066:  brfalse.s  IL_0075
            //IL_0068:  ldarg.3
            //IL_0069:  ldc.r8     (00 00 00 00 00 00 F8 FF)
            //IL_0072:  stind.r8
            //IL_0073:  br.s       IL_0077
            //IL_0075:  ldc.i4.0
            //IL_0076:  ret
            //IL_0077:  ldc.i4.1
            //IL_0078:  ret
            bool V_0;
            string V_1;
            if (s == null)
            {
                result = 0.0d;
                return false;
            }
            else
            {
                V_0 = System.Number.TryParseDouble(s, style, info, out result);
                if (V_0)
                {
                    return true;
                }
                else
                {
                    //IL_0019
                    V_1 = s.Trim();
                    if (V_1.Equals(info.PositiveInfinitySymbol))
                    {
                        result = double.PositiveInfinity;
                    }
                    else if (V_1.Equals(info.NegativeInfinitySymbol))
                    {
                        result = double.NegativeInfinity;
                    }
                    else if (V_1.Equals(info.NaNSymbol))
                    {
                        result = double.NaN;
                   }
                    else
                    {
                        return false;
                    }
                    return true;
                }
            }
        }
        public new virtual sealed System.TypeCode GetTypeCode()
        {
            //.maxstack  8
            //IL_0000:  ldc.i4.s   14
            //IL_0002:  ret
            return TypeCode.Double;
        }
        private new virtual sealed bool System.IConvertible.ToBoolean(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToBoolean
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       bool System.Convert::ToBoolean(float64)
            //IL_0007:  ret
            return System.Convert.ToBoolean(this);
        }
        private new virtual sealed char System.IConvertible.ToChar(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToChar
            //.maxstack  5
            //.locals init (object[] V_0)
            //IL_0000:  call       class System.Globalization.CultureInfo System.Globalization.CultureInfo::get_CurrentCulture()
            //IL_0005:  ldstr      "InvalidCast_FromTo"
            //IL_000a:  call       string System.Environment::GetResourceString(string)
            //IL_000f:  ldc.i4.2
            //IL_0010:  newarr     System.Object
            //IL_0015:  stloc.0
            //IL_0016:  ldloc.0
            //IL_0017:  ldc.i4.0
            //IL_0018:  ldstr      "Double"
            //IL_001d:  stelem.ref
            //IL_001e:  ldloc.0
            //IL_001f:  ldc.i4.1
            //IL_0020:  ldstr      "Char"
            //IL_0025:  stelem.ref
            //IL_0026:  ldloc.0
            //IL_0027:  call       string System.String::Format(class System.IFormatProvider,
            //string,
            //object[])
            //IL_002c:  newobj     instance void System.InvalidCastException::.ctor(string)
            //IL_0031:  throw
            object[] V_0;
            V_0 = new object[2];
            V_0[0] = "Double";
            V_0[1] = "Char";
            throw new System.InvalidCastException(string.Format(CultureInfo.CurrentCulture, System.Environment.GetResourceString("InvalidCast_FromTo"), V_0));
        }
        private new virtual sealed sbyte System.IConvertible.ToSByte(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToSByte
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       int8 System.Convert::ToSByte(float64)
            //IL_0007:  ret
            return System.Convert.ToSByte(this);
        }
        private new virtual sealed byte System.IConvertible.ToByte(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToByte
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       uint8 System.Convert::ToByte(float64)
            //IL_0007:  ret
            return System.Convert.ToByte(this);
        }
        private new virtual sealed short System.IConvertible.ToInt16(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToInt16
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       int16 System.Convert::ToInt16(float64)
            //IL_0007:  ret
            return System.Convert.ToInt16(this);
        }
        private new virtual sealed ushort System.IConvertible.ToUInt16(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToUInt16
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       uint16 System.Convert::ToUInt16(float64)
            //IL_0007:  ret
            return System.Convert.ToUInt16(this);
        }
        privat new virtual sealed int System.IConvertible.ToInt32(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToInt32
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       int32 System.Convert::ToInt32(float64)
            //IL_0007:  ret
            return System.Convert.ToInt32(this);
        }
        private new virtual sealed uint System.IConvertible.ToUInt32(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToUInt32
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       uint32 System.Convert::ToUInt32(float64)
            //IL_0007:  ret
            return System.Convert.ToUInt32(this);
        }
        private new virtual sealed long System.IConvertible.ToInt64(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToInt64
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       int64 System.Convert::ToInt64(float64)
            //IL_0007:  ret
            return System.Convert.ToInt64(this);
        }
        private new virtual sealed ulong System.IConvertible.ToUInt64(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToUInt64
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       uint64 System.Convert::ToUInt64(float64)
            //IL_0007:  ret
            return System.Convert.ToUInt64(this);
        }
        private new virtual sealed float System.IConvertible.ToSingle(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToSingle
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       float32 System.Convert::ToSingle(float64)
            //IL_0007:  ret
            return System.Convert.ToSingle(this);
        }
        private new virtual sealed double System.IConvertible.ToDouble(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToDouble
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  ret
            return this;
        }
        private new virtual sealed System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToDecimal
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  call       valuetype System.Decimal System.Convert::ToDecimal(float64)
            //IL_0007:  ret
            return System.Convert.ToDecimal(this);
        }
        private new virtual sealed System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToDateTime
            //.maxstack  5
            //.locals init (object[] V_0)
            //IL_0000:  call       class System.Globalization.CultureInfo System.Globalization.CultureInfo::get_CurrentCulture()
            //IL_0005:  ldstr      "InvalidCast_FromTo"
            //IL_000a:  call       string System.Environment::GetResourceString(string)
            //IL_000f:  ldc.i4.2
            //IL_0010:  newarr     System.Object
            //IL_0015:  stloc.0
            //IL_0016:  ldloc.0
            //IL_0017:  ldc.i4.0
            //IL_0018:  ldstr      "Double"
            //IL_001d:  stelem.ref
            //IL_001e:  ldloc.0
            //IL_001f:  ldc.i4.1
            //IL_0020:  ldstr      "DateTime"
            //IL_0025:  stelem.ref
            //IL_0026:  ldloc.0
            //IL_0027:  call       string System.String::Format(class System.IFormatProvider,
            //string,
            //object[])
            //IL_002c:  newobj     insance void System.InvalidCastException::.ctor(string)
            //IL_0031:  throw
            object[] V_0;
            V_0 = new object[2];
            V_0[0] = "Double";
            V_0[1] = "DateTime";
            throw new System.InvalidCastException(string.Format(CultureInfo.CurrentCulture, System.Environment.GetResourceString("InvalidCast_FromTo"), V_0));
        }
        private new virtual sealed object System.IConvertible.ToType(System.Type @type, System.IFormatProvider provider)
        {
            //.override System.IConvertible::ToType
            //.maxstack  8
            //IL_0000:  ldarg.0
            //IL_0001:  ldind.r8
            //IL_0002:  box        System.Double
            //IL_0007:  ldarg.1
            //IL_0008:  ldarg.2
            //IL_0009:  call       object System.Convert::DefaultToType(class System.IConvertible,
            //class System.Type,
            //class System.IFormatProvider)
            //IL_000e:  ret
            return System.Convert.DefaultToType((System.IConvertible)this, @type, provider); 
        }
        private static Double()
        {
            //.maxstack  8
            //IL_0000:  ldc.i8     0x8000000000000000
            //IL_0009:  call       float64 System.BitConverter::Int64BitsToDouble(int64)
            //IL_000e:  stsfld     float64 System.Double::NegativeZero
            //IL_0013:  ret
            System.Double.NegativeZero=System.BitConverter.Int64BitsToDouble(0x8000000000000000);
        }
    }
}

转载于:https://www.cnblogs.com/MSIL/articles/1811126.html

<think>我们遇到了一个类型转换错误:`Unable to cast System.Single to System.Double`。这个错误发生在尝试为NumericUpDown控件的Value属性设置一个Single类型(即float)的值时,而该属性期望的是Double类型(在WPF中可能是decimal或double,具体取决于控件)。在.NET中,NumericUpDown控件(无论是Windows Forms还是WPF)的Value属性通常是decimal类型(Windows Forms)或double类型(WPF)。但是,错误信息明确指出尝试将Single转换为Double,这表明我们可能在使用WPF的NumericUpDown(因为它的Value是double类型),并且我们试图将一个float(Single)值赋给它,而.NET不允许隐式转换float到double?实际上,在C#中,float可以隐式转换为double,所以这个错误可能另有原因。 然而,错误信息是“Unable to cast System.Single to System.Double”,这通常意味着我们尝试使用强制转换(cast)将Single转换为Double,但转换失败。但实际上,在C#中,float(Single)可以隐式转换为doubleDouble),所以通常不会出现InvalidCastException。因此,这个错误可能发生在其他场景,比如在数据绑定或反射时。 但是,根据用户提供的引用[1]中提到的错误:`Unable to cast object of type 'System.Int32' to type 'System.Array'`,这是一个InvalidCastException,通常发生在尝试将一个非数组对象强制转换为数组类型时。同样,用户现在遇到的错误是尝试将Single(float)转换为Doubledouble)时出现InvalidCastException,这同样是不合理的,因为float可以隐式转double。所以,我们可能需要考虑以下情况: 1. 数据绑定上下文:可能是在数据绑定中,源属性是float类型,而目标属性(NumericUpDown.Value)是double类型,但绑定引擎在转换时出错。 2. 使用反射设置属性:可能通过反射设置Value属性,而反射要求类型完全匹配或可转换,但可能由于某种原因转换失败。 3. 控件内部实现:可能是控件内部在处理值时进行了某种转换,而该转换不支持。 但是,用户提到错误发生在“设置控件值时”,所以可能是直接赋值或通过绑定赋值。 **重新分析问题**:用户说“设置值时控件报错”,并提到之前的错误是关于NumericUpDownValue的,现在又提到类型转换错误(System.InvalidCastException: 无法将System.Single转换为System.Double)。所以,我们可能需要关注赋值时的类型。 在Windows Forms中,NumericUpDown控件的Value属性是decimal类型。在WPF中,如果使用扩展工具包(如Extended WPF Toolkit)中的NumericUpDown控件,它的Value属性是double类型。因此,如果我们尝试将一个float值赋给一个decimal属性(Windows Forms)或double属性(WPF),按理说C#会进行隐式转换(float到double可以隐式转换,但float到decimal不能隐式转换,需要显式转换)。所以,如果是在Windows Forms中,我们试图将float赋值给decimal,则编译器会报错(编译时错误),而不是运行时InvalidCastException。但是,如果通过反射赋值,则可能会在运行时抛出InvalidCastException。 因此,我们假设用户使用的是WPF的NumericUpDown(因为Value是double),并且通过某种方式(可能是反射或数据绑定)设置值,而该方式要求显式转换。 **解决方案**: 1. **显式转换**:在赋值前,将float显式转换为double(尽管隐式转换通常可行,但为了清晰和避免反射问题,可以显式转换)。 2. **检查赋值方式**:如果直接赋值,确保类型正确。如果通过数据绑定,检查绑定转换器。 3. **使用转换器**:在数据绑定时,如果源类型和目标类型不匹配,可以使用值转换器(IValueConverter)。 ### 详细步骤 #### 情况1:直接代码赋值 如果是在代码中直接设置控件的Value,并且确定控件是WPF的NumericUpDown(Value为double),那么可以这样: ```csharp float myValue = 68.57f; // 假设有一个float值 numericUpDown1.Value = (double)myValue; // 显式转换为double ``` 或者,由于float到double是隐式的,也可以直接赋值: ```csharp numericUpDown1.Value = myValue; // 隐式转换 ``` 但为什么会出现InvalidCastException呢?可能是因为在赋值过程中,值被装箱后再拆箱到double,而拆箱要求类型完全匹配。例如: ```csharp object boxedValue = myValue; // 装箱为float // 然后尝试拆箱为double double unboxedValue = (double)boxedValue; // 这里会抛出InvalidCastException,因为拆箱必须到相同的类型 ``` 所以,如果赋值过程中有装箱拆箱操作(比如通过反射或非泛型集合),则会出现此问题。 #### 情况2:通过反射设置属性 如果使用反射设置属性,则必须确保类型匹配。例如: ```csharp var propertyInfo = numericUpDown1.GetType().GetProperty("Value"); float myValue = 68.57f; // 下面这行会抛出InvalidCastException,因为反射的SetValue方法要求提供的值类型与属性类型完全匹配或可转换,但float到double的转换在反射中可能不被支持 propertyInfo.SetValue(numericUpDown1, myValue); ``` 解决方法:在反射赋值前,将值转换为目标类型: ```csharp propertyInfo.SetValue(numericUpDown1, (double)myValue); ``` #### 情况3:数据绑定 如果使用数据绑定,则可以在绑定中使用转换器: XAML: ```xml <Window.Resources> <local:FloatToDoubleConverter x:Key="FloatToDoubleConverter"/> </Window.Resources> ... <extended:NumericUpDown Value="{Binding MyFloatValue, Converter={StaticResource FloatToDoubleConverter}}" /> ``` 转换器实现: ```csharp public class FloatToDoubleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { // 从源到目标:float -> double if (value is float) { return (double)(float)value; } return value; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { // 从目标到源:double -> float if (value is double) { return (float)(double)value; } return value; } } ``` ### 总结 - **根本原因**:在设置NumericUpDown的Value属性时,传入的值是System.Single(float),但属性期望的是System.Doubledouble)。在直接赋值时,C#会进行隐式转换,但若赋值过程中涉及装箱拆箱(如反射、集合等)则会导致InvalidCastException。 - **解决方法**: 1. 在赋值前显式将float转换为double。 2. 如果通过反射赋值,确保传入转换后的double值。 3. 如果使用数据绑定,使用转换器进行类型转换。 ### 注意事项 - 在Windows Forms中,NumericUpDown的Value是decimal类型,因此不能直接赋值float,必须先转换为decimal(但转换可能损失精度)。例如: ```csharp float myValue = 68.57f; numericUpDown1.Value = (decimal)myValue; // 显式转换为decimal ``` 注意:float到decimal的转换可能会导致精度损失,因为float的精度较低。 ### 相关问题 1. 如何在WPF中正确使用NumericUpDown控件? 2. 数据绑定中类型不匹配的常见解决方法有哪些? 3..NET中,值类型之间的转换规则是什么?</think>### 解决 "Unable to cast System.Single to System.Double" 类型转换错误 您在设置 NumericUpDown 控件值时遇到的 `System.InvalidCastException` 错误,本质上是由于 .NET 类型系统无法直接将单精度浮点数(Single/float)转换为双精度浮点数(Double),尤其是在控件属性要求特定数值类型时发生。结合引用[1]和[2]的信息,以下是深度分析和解决方案: --- #### 问题根源分析 1. **类型系统不匹配**: - `System.Single` (float, 32位) 和 `System.Double` (double, 64位) 是两种不同的浮点类型 - NumericUpDown 的 `Value` 属性通常要求 `decimal` 或 `double` 类型(取决于控件实现) - 直接赋值时,.NET 不会自动在浮点类型间转换,导致 `InvalidCastException`[^1] 2. **精度差异引发的陷阱**: - 如引用[2]所述,浮点类型转换易丢失精度(如 `68.56999969482422`) - 控件内部可能使用 `decimal` 类型存储值(精确十进制),而您的数据源是 `float`[^2] 3. **常见触发场景**: ```csharp float externalValue = 68.57f; // 来自外部数据源 numericUpDown.Value = externalValue; // 抛出 InvalidCastException ``` --- #### 解决方案(分步骤实现) ##### 方法1:显式类型转换(推荐) ```csharp float sourceValue = GetFloatValue(); // 从数据源获取 float 值 // 方案1:转换为 double(适合 WPF 的 NumericUpDown) numericUpDown.Value = (double)sourceValue; // 方案2:转换为 decimal(适合 WinForms 的 NumericUpDown) numericUpDown.Value = (decimal)sourceValue; ``` ##### 方法2:使用 `Convert` 类(自动处理边界值) ```csharp float sourceValue = 68.57f; numericUpDown.Value = Convert.ToDecimal(sourceValue); // 自动转换 + 溢出检查 ``` ##### 方法3:数据绑定时的类型转换器(WPF/MVVM 场景) ```csharp // 在 XAML 中绑定使用转换器 <nu:NumericUpDown Value="{Binding Path=FloatValue, Converter={StaticResource FloatToDoubleConverter}}"/> // 转换器实现 public class FloatToDoubleConverter : IValueConverter { public object Convert(object value, Type targetType, object p, CultureInfo c) { return System.Convert.ToDouble(value); // float → double } public object ConvertBack(...) { ... } } ``` ##### 方法4:全局处理浮点精度(解决如 68.56999969482422 的精度问题) ```csharp decimal SafeConvert(float value) { // 四舍五入到小数点后4位,避免浮点误差 return (decimal)Math.Round(value, 4); } numericUpDown.Value = SafeConvert(68.56999969482422f); ``` --- #### 关键预防措施 1. **类型一致性检查**: ```csharp if (externalValue is float) { numericUpDown.Value = (decimal)(float)externalValue; } ``` 2. **控件初始化规范**: ```csharp numericUpDown.Minimum = 0m; // 明确使用 decimal 字面量 numericUpDown.Maximum = 100m; numericUpDown.DecimalPlaces = 4; // 显式设置小数位数 ``` 3. **数据源类型验证**: ```csharp var value = dataSource.GetValue(); if (value.GetType() != typeof(decimal)) { throw new InvalidOperationException("需要 decimal 类型数据源"); } ``` --- #### 数学原理说明 浮点数转换的误差问题源于二进制表示差异: $$ \text{float} \rightarrow \text{double} : \quad x_{\text{float}} = x \pm \epsilon_{\text{float}} $$ $$ \text{转换后} : \quad x_{\text{double}} = x \pm \epsilon_{\text{float}} + \delta $$ 其中 $\delta$ 是二次转换误差。使用 `decimal` 可避免此问题,因其采用十进制表示法[^2]。 --- #### 相关问题 1. 如何正确处理 WinForms 和 WPF 中 NumericUpDown 控件的类型差异? 2. 在数据库交互时如何避免浮点数精度丢失问题? 3. 如何为 NumericUpDown 创建自定义类型安全包装器? 4. 为什么在 JSON 序列化中浮点数容易丢失精度?如何解决?[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值