File: Microsoft\VisualBasic\CompilerServices\DecimalType.vb
Web Access
Project: src\src\libraries\Microsoft.VisualBasic.Core\src\Microsoft.VisualBasic.Core.vbproj (Microsoft.VisualBasic.Core)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
 
Imports System
Imports System.Globalization
Imports Microsoft.VisualBasic.CompilerServices.ExceptionUtils
Imports Microsoft.VisualBasic.CompilerServices.Utils
 
Namespace Microsoft.VisualBasic.CompilerServices
 
    <System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)>
    Public NotInheritable Class DecimalType
        ' Prevent creation.
        Private Sub New()
        End Sub
 
        Public Shared Function FromBoolean(ByVal Value As Boolean) As Decimal
            If Value Then
                Return -1D
            Else
                Return 0D
            End If
        End Function
 
        Public Shared Function FromString(ByVal Value As String) As Decimal
            Return FromString(Value, Nothing)
        End Function
 
        Public Shared Function FromString(ByVal Value As String, ByVal NumberFormat As NumberFormatInfo) As Decimal
            If Value Is Nothing Then
                Return 0D
            End If
 
            Try
                Dim i64Value As Int64
 
                If IsHexOrOctValue(Value, i64Value) Then
                    Return CDec(i64Value)
                End If
 
                Return Parse(Value, NumberFormat)
 
            Catch e1 As OverflowException
                Throw VbMakeException(vbErrors.Overflow)
            Catch e2 As FormatException
                Throw New InvalidCastException(SR.Format(SR.InvalidCast_FromStringTo, Left(Value, 32), "Decimal"))
            End Try
        End Function
 
        Public Shared Function FromObject(ByVal Value As Object) As Decimal
            Return FromObject(Value, Nothing)
        End Function
 
        Public Shared Function FromObject(ByVal Value As Object, ByVal NumberFormat As NumberFormatInfo) As Decimal
 
            If Value Is Nothing Then
                Return 0D
            End If
 
            Dim valueInterface As IConvertible
            Dim valueTypeCode As TypeCode
 
            valueInterface = TryCast(Value, IConvertible)
 
            If Not valueInterface Is Nothing Then
 
                valueTypeCode = valueInterface.GetTypeCode()
 
                Select Case valueTypeCode
 
                    Case TypeCode.Boolean
                        Return DecimalType.FromBoolean(valueInterface.ToBoolean(Nothing))
 
                    Case TypeCode.Byte
                        Return CDec(valueInterface.ToByte(Nothing))
 
                    Case TypeCode.Int16
                        Return CDec(valueInterface.ToInt16(Nothing))
 
                    Case TypeCode.Int32
                        Return CDec(valueInterface.ToInt32(Nothing))
 
                    Case TypeCode.Int64
                        Return CDec(valueInterface.ToInt64(Nothing))
 
                    Case TypeCode.Single
                        Return CDec(valueInterface.ToSingle(Nothing))
 
                    Case TypeCode.Double
                        Return CDec(valueInterface.ToDouble(Nothing))
 
                    Case TypeCode.Decimal
                        Return valueInterface.ToDecimal(Nothing)
 
                    Case TypeCode.String
                        Return DecimalType.FromString(valueInterface.ToString(Nothing), NumberFormat)
 
                    Case TypeCode.Char,
                         TypeCode.DateTime
                        ' Fall through to error                        
                    Case Else
                        ' Fall through to error
                End Select
            End If
 
            Throw New InvalidCastException(SR.Format(SR.InvalidCast_FromTo, VBFriendlyName(Value), "Decimal"))
        End Function
 
        Public Shared Function Parse(ByVal Value As String, ByVal NumberFormat As NumberFormatInfo) As Decimal
            Dim normalizedNumberFormat As NumberFormatInfo
            Dim culture As CultureInfo = GetCultureInfo()
 
            If NumberFormat Is Nothing Then
                NumberFormat = culture.NumberFormat
            End If
 
            ' Normalize number format settings to enable us to first use the numeric settings for both currency and number parsing
            ' compatible with VB6
            normalizedNumberFormat = GetNormalizedNumberFormat(NumberFormat)
 
            Const flags As NumberStyles =
                    NumberStyles.AllowDecimalPoint Or
                    NumberStyles.AllowExponent Or
                    NumberStyles.AllowLeadingSign Or
                    NumberStyles.AllowLeadingWhite Or
                    NumberStyles.AllowThousands Or
                    NumberStyles.AllowTrailingSign Or
                    NumberStyles.AllowParentheses Or
                    NumberStyles.AllowTrailingWhite Or
                    NumberStyles.AllowCurrencySymbol
 
            Value = ToHalfwidthNumbers(Value, culture)
 
            Try
                ' Use numeric settings to parse
                Return System.Decimal.Parse(Value, flags, normalizedNumberFormat)
            Catch FormatEx As FormatException When Not (NumberFormat Is normalizedNumberFormat)
                ' Use currency settings to parse
                Return System.Decimal.Parse(Value, flags, NumberFormat)
            Catch Ex As Exception
                Throw Ex
            End Try
 
        End Function
 
        '  This method returns a NumberFormat with the relevant Currency Settings to be the same as the Number Settings
        '  In - NumberFormat to be normalized - this is not changed by this Method
        '  Return - Normalized NumberFormat
        Friend Shared Function GetNormalizedNumberFormat(ByVal InNumberFormat As NumberFormatInfo) As NumberFormatInfo
 
            Dim outNumberFormat As NumberFormatInfo
 
            With InNumberFormat
                If (Not .CurrencyDecimalSeparator Is Nothing) AndAlso
                   (Not .NumberDecimalSeparator Is Nothing) AndAlso
                   (Not .CurrencyGroupSeparator Is Nothing) AndAlso
                   (Not .NumberGroupSeparator Is Nothing) AndAlso
                   (.CurrencyDecimalSeparator.Length = 1) AndAlso
                   (.NumberDecimalSeparator.Length = 1) AndAlso
                   (.CurrencyGroupSeparator.Length = 1) AndAlso
                   (.NumberGroupSeparator.Length = 1) AndAlso
                   (.CurrencyDecimalSeparator.Chars(0) = .NumberDecimalSeparator.Chars(0)) AndAlso
                   (.CurrencyGroupSeparator.Chars(0) = .NumberGroupSeparator.Chars(0)) AndAlso
                   (.CurrencyDecimalDigits = .NumberDecimalDigits) Then
                    Return InNumberFormat
                End If
            End With
 
 
            With InNumberFormat
                If (Not .CurrencyDecimalSeparator Is Nothing) AndAlso
                   (Not .NumberDecimalSeparator Is Nothing) AndAlso
                   (.CurrencyDecimalSeparator.Length = .NumberDecimalSeparator.Length) AndAlso
                   (Not .CurrencyGroupSeparator Is Nothing) AndAlso
                   (Not .NumberGroupSeparator Is Nothing) AndAlso
                   (.CurrencyGroupSeparator.Length = .NumberGroupSeparator.Length) Then
 
                    Dim i As Integer
                    For i = 0 To .CurrencyDecimalSeparator.Length - 1
                        If (.CurrencyDecimalSeparator.Chars(i) <> .NumberDecimalSeparator.Chars(i)) Then GoTo MisMatch
                    Next
 
                    For i = 0 To .CurrencyGroupSeparator.Length - 1
                        If (.CurrencyGroupSeparator.Chars(i) <> .NumberGroupSeparator.Chars(i)) Then GoTo MisMatch
                    Next
 
                    Return InNumberFormat
                End If
            End With
 
MisMatch:
 
            outNumberFormat = DirectCast(InNumberFormat.Clone, NumberFormatInfo)
 
            ' Set the Currency Settings to be the Same as the Numeric Settings
            With outNumberFormat
                .CurrencyDecimalSeparator = .NumberDecimalSeparator
                .CurrencyGroupSeparator = .NumberGroupSeparator
                .CurrencyDecimalDigits = .NumberDecimalDigits
            End With
 
            Return outNumberFormat
        End Function
 
    End Class
 
End Namespace