File: Microsoft\VisualBasic\CompilerServices\DecimalType.vb
Web Access
Project: src\runtime\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