Compartir a través de


Clase NumberFormatInfo

En este artículo, se proporcionan comentarios adicionales a la documentación de referencia de esta API.

La clase NumberFormatInfo contiene información específica de la referencia cultural que se usa al dar formato a los valores numéricos y analizarlos. Esta información incluye el símbolo de moneda, el símbolo decimal, el símbolo separador de grupo y los símbolos de signos positivos y negativos.

Crear una instancia de un objeto NumberFormatInfo

Puede crear instancias de un objeto NumberFormatInfo que represente las convenciones de formato de la referencia cultural actual, la referencia cultural invariable, una referencia cultural específica o una referencia cultural neutra.

Crear una instancia de un objeto NumberFormatInfo para la referencia cultural actual

Puede crear instancias de un objeto NumberFormatInfo para la referencia cultural actual de cualquiera de las maneras siguientes. En cada caso, el objeto devuelto NumberFormatInfo es de solo lectura.

En el ejemplo siguiente se usan estas tres maneras de crear NumberFormatInfo objetos que representan las convenciones de formato de la referencia cultural actual. También recupera el valor de la propiedad IsReadOnly para ilustrar que cada objeto es de solo lectura.

using System;
using System.Globalization;

public class InstantiateEx1
{
    public static void Main()
    {
        NumberFormatInfo current1 = CultureInfo.CurrentCulture.NumberFormat;
        Console.WriteLine(current1.IsReadOnly);

        NumberFormatInfo current2 = NumberFormatInfo.CurrentInfo;
        Console.WriteLine(current2.IsReadOnly);

        NumberFormatInfo current3 = NumberFormatInfo.GetInstance(CultureInfo.CurrentCulture);
        Console.WriteLine(current3.IsReadOnly);
    }
}
// The example displays the following output:
//       True
//       True
//       True

Puede crear un objeto grabable NumberFormatInfo que represente las convenciones de la referencia cultural actual de cualquiera de las maneras siguientes:

En el ejemplo siguiente se muestran estas dos formas de crear instancias de un objetoNumberFormatInfo y se muestra el valor de su propiedad IsReadOnly para ilustrar que el objeto no es de solo lectura.

using System;
using System.Globalization;

public class InstantiateEx2
{
    public static void Main()
    {
        NumberFormatInfo current1 = NumberFormatInfo.CurrentInfo;
        current1 = (NumberFormatInfo)current1.Clone();
        Console.WriteLine(current1.IsReadOnly);

        CultureInfo culture2 = CultureInfo.CreateSpecificCulture(CultureInfo.CurrentCulture.Name);
        NumberFormatInfo current2 = culture2.NumberFormat;
        Console.WriteLine(current2.IsReadOnly);
    }
}
// The example displays the following output:
//       False
//       False

Tenga en cuenta que el sistema operativo Windows permite al usuario invalidar algunos de los valores de propiedad NumberFormatInfousados en las operaciones de formato numérico y análisis a través del elemento Región y Idioma en el Panel de control. Por ejemplo, un usuario cuya referencia cultural es inglés (Estados Unidos) podría optar por mostrar valores de moneda como 1,1 USD en lugar del valor predeterminado de 1,1 USD. Los objetos NumberFormatInfo recuperados de las maneras descritas anteriormente reflejan estas invalidaciones de usuario. Si esto no es deseable, puede crear un objeto NumberFormatInfo que no refleje invalidaciones de usuario (y que también sea de lectura y escritura en lugar de solo lectura) llamando al constructor CultureInfo.CultureInfo(String, Boolean) y proporcionando un valor false para el argumento useUserOverride. En el ejemplo siguiente se proporciona una ilustración para un sistema cuya referencia cultural actual es inglés (Estados Unidos) y cuyo símbolo de moneda se ha cambiado del valor predeterminado de $ a USD.

using System;
using System.Globalization;

public class InstantiateEx3
{
    public static void Main()
    {
        CultureInfo culture;
        NumberFormatInfo nfi;

        culture = CultureInfo.CurrentCulture;
        nfi = culture.NumberFormat;
        Console.WriteLine("Culture Name:    {0}", culture.Name);
        Console.WriteLine("User Overrides:  {0}", culture.UseUserOverride);
        Console.WriteLine("Currency Symbol: {0}\n", culture.NumberFormat.CurrencySymbol);

        culture = new CultureInfo(CultureInfo.CurrentCulture.Name, false);
        Console.WriteLine("Culture Name:    {0}", culture.Name);
        Console.WriteLine("User Overrides:  {0}", culture.UseUserOverride);
        Console.WriteLine("Currency Symbol: {0}", culture.NumberFormat.CurrencySymbol);
    }
}
// The example displays the following output:
//       Culture Name:    en-US
//       User Overrides:  True
//       Currency Symbol: USD
//
//       Culture Name:    en-US
//       User Overrides:  False
//       Currency Symbol: $

Si la Propiedad CultureInfo.UseUserOverride se establece en true, las propiedades CultureInfo.DateTimeFormat, CultureInfo.NumberFormat, y CultureInfo.TextInfo también se recuperan de la configuración del usuario. Si la configuración del usuario no es compatible con la referencia cultural asociada al objeto CultureInfo (por ejemplo, si el calendario seleccionado no es uno de los calendarios enumerados por la propiedad OptionalCalendars), los resultados de los métodos y los valores de las propiedades no están definidos.

Crear una instancia de un objeto NumberFormatInfo para la referencia cultural invariable

La referencia cultural invariable representa una referencia cultural que no distingue la referencia cultural. Se basa en el idioma inglés, pero no en ningún país o región específicos de habla inglesa. Aunque los datos de referencias culturales específicas pueden ser dinámicos y cambiar para reflejar nuevas convenciones culturales o preferencias de usuario, los datos de la referencia cultural invariable no cambian. Un objeto NumberFormatInfo que representa las convenciones de formato de la referencia cultural invariable se puede usar para las operaciones de formato en las que las cadenas de resultado no deben variar según la referencia cultural.

Puede crear instancias de un objeto NumberFormatInfo que represente las convenciones de formato de la referencia cultural invariable de las siguientes maneras:

En el siguiente ejemplo se usa cada uno de estos métodos para crear instancias de un objeto NumberFormatInfo que representa la referencia cultural invariable. A continuación, indica si el objeto es de solo lectura,

using System;
using System.Globalization;

public class InstantiateEx4
{
    public static void Main()
    {
        NumberFormatInfo nfi;

        nfi = System.Globalization.NumberFormatInfo.InvariantInfo;
        Console.WriteLine(nfi.IsReadOnly);

        nfi = CultureInfo.InvariantCulture.NumberFormat;
        Console.WriteLine(nfi.IsReadOnly);

        nfi = new NumberFormatInfo();
        Console.WriteLine(nfi.IsReadOnly);
    }
}
// The example displays the following output:
//       True
//       True
//       False

Crear una instancia de un objeto NumberFormatInfo para una referencia cultural específica

Una referencia cultural específica representa un idioma que se habla en un país o región determinado. Por ejemplo, en-US es una referencia cultural específica que representa el inglés hablado en los Estados Unidos y en-CA es una referencia cultural específica que representa el inglés hablado en Canadá. Puede crear instancias de un objeto NumberFormatInfo que represente las convenciones de formato de una referencia cultural específica de las siguientes maneras:

En el ejemplo siguiente se usan estas cuatro maneras de crear un objeto NumberFormatInfo que refleje las convenciones de formato de la referencia cultural indonesia (Indonesia). También indica si cada objeto es de solo lectura.

using System;
using System.Globalization;

public class InstantiateEx5
{
    public static void Main()
    {
        CultureInfo culture;
        NumberFormatInfo nfi;

        nfi = CultureInfo.GetCultureInfo("id-ID").NumberFormat;
        Console.WriteLine("Read-only: {0}", nfi.IsReadOnly);

        culture = new CultureInfo("id-ID");
        nfi = NumberFormatInfo.GetInstance(culture);
        Console.WriteLine("Read-only: {0}", nfi.IsReadOnly);

        culture = CultureInfo.CreateSpecificCulture("id-ID");
        nfi = culture.NumberFormat;
        Console.WriteLine("Read-only: {0}", nfi.IsReadOnly);

        culture = new CultureInfo("id-ID");
        nfi = culture.NumberFormat;
        Console.WriteLine("Read-only: {0}", nfi.IsReadOnly);
    }
}
// The example displays the following output:
//       Read-only: True
//       Read-only: False
//       Read-only: False
//       Read-only: False

Crear una instancia de un objeto NumberFormatInfo para una referencia cultural neutra

Una referencia cultural neutral representa una referencia cultural o un idioma que es independiente de un país o región. Normalmente es el elemento primario de una o varias referencias culturales específicas. Por ejemplo, Fr es una referencia cultural neutra para el idioma francés y el elemento primario de la referencia cultural fr-FR. Cree un objeto NumberFormatInfo que representa las convenciones de formato de una referencia cultural neutra de la misma manera que crea un objeto NumberFormatInfo que representa las convenciones de formato de una referencia cultural específica.

Sin embargo, dado que es independiente de un país o región específicos, una referencia cultural neutral carece de información de formato específica de la referencia cultural. En lugar de rellenar el objeto NumberFormatInfo con valores genéricos, .NET devuelve un objeto NumberFormatInfo que refleja las convenciones de formato de una referencia cultural específica que es un elemento secundario de la referencia cultural neutra. Por ejemplo, el objeto NumberFormatInfo de la referencia cultural neutra refleja las convenciones de formato de la referencia cultural en-US y el objeto NumberFormatInfo para la referencia cultural fr refleja las convenciones de formato de la referencia cultural fr-FR.

Puede usar código como el siguiente para determinar qué convenciones de formato de referencia cultural específicas representa cada referencia cultural neutra.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;

public class InstantiateEx6
{
    public static void Main()
    {
        // Get all the neutral cultures
        List<String> names = new List<String>();
        Array.ForEach(CultureInfo.GetCultures(CultureTypes.NeutralCultures),
                      culture => names.Add(culture.Name));
        names.Sort();
        foreach (var name in names)
        {
            // Ignore the invariant culture.
            if (name == "") continue;

            ListSimilarChildCultures(name);
        }
    }

    private static void ListSimilarChildCultures(string name)
    {
        // Create the neutral NumberFormatInfo object.
        NumberFormatInfo nfi = CultureInfo.GetCultureInfo(name).NumberFormat;
        // Retrieve all specific cultures of the neutral culture.
        CultureInfo[] cultures = Array.FindAll(CultureInfo.GetCultures(CultureTypes.SpecificCultures),
                                 culture => culture.Name.StartsWith(name + "-", StringComparison.OrdinalIgnoreCase));
        // Create an array of NumberFormatInfo properties
        PropertyInfo[] properties = typeof(NumberFormatInfo).GetProperties(BindingFlags.Instance | BindingFlags.Public);
        bool hasOneMatch = false;

        foreach (var ci in cultures)
        {
            bool match = true;
            // Get the NumberFormatInfo for a specific culture.
            NumberFormatInfo specificNfi = ci.NumberFormat;
            // Compare the property values of the two.
            foreach (var prop in properties)
            {
                // We're not interested in the value of IsReadOnly.
                if (prop.Name == "IsReadOnly") continue;

                // For arrays, iterate the individual elements to see if they are the same.
                if (prop.PropertyType.IsArray)
                {
                    IList nList = (IList)prop.GetValue(nfi, null);
                    IList sList = (IList)prop.GetValue(specificNfi, null);
                    if (nList.Count != sList.Count)
                    {
                        match = false;
                        break;
                    }

                    for (int ctr = 0; ctr < nList.Count; ctr++)
                    {
                        if (!nList[ctr].Equals(sList[ctr]))
                        {
                            match = false;
                            break;
                        }
                    }
                }
                else if (!prop.GetValue(specificNfi).Equals(prop.GetValue(nfi)))
                {
                    match = false;
                    break;
                }
            }
            if (match)
            {
                Console.WriteLine("NumberFormatInfo object for '{0}' matches '{1}'",
                                          name, ci.Name);
                hasOneMatch = true;
            }
        }
        if (!hasOneMatch)
            Console.WriteLine("NumberFormatInfo object for '{0}' --> No Match", name);

        Console.WriteLine();
    }
}

Datos dinámicos

Los datos específicos de la referencia cultural para dar formato a los valores numéricos proporcionados por la clase NumberFormatInfoson dinámicos, al igual que los datos culturales proporcionados por la clase CultureInfo. No debe realizar ninguna suposición sobre la estabilidad de los valores de los objetos NumberFormatInfo asociados a determinados objetos CultureInfo. Solo los datos proporcionados por la referencia cultural invariable y su objeto NumberFormatInfo asociado son estables. Otros datos pueden cambiar entre sesiones de aplicación, o incluso dentro de una sola sesión, por los siguientes motivos:

  • Actualizaciones del sistema. Las preferencias culturales, como el símbolo de moneda o los formatos de moneda cambian con el tiempo. Cuando esto sucede, Windows Update incluye cambios en el valor de propiedad NumberFormatInfo de una referencia cultural determinada.

  • Referencias culturales de reemplazo. La clase CultureAndRegionInfoBuilder se puede usar para reemplazar los datos de una referencia cultural existente.

  • Cambios en cascada en los valores de propiedad. Varias propiedades relacionadas con la referencia cultural pueden cambiar en tiempo de ejecución, lo que, a su vez, hace que los datos NumberFormatInfo cambien. Por ejemplo, la referencia cultural actual se puede cambiar mediante programación o a través de la acción del usuario. Cuando esto sucede, el objeto NumberFormatInfo devuelto por la propiedad CurrentInfo cambia a un objeto asociado a la referencia cultural actual.

  • Preferencias del usuario. Los usuarios de la aplicación pueden invalidar algunos de los valores asociados a la referencia cultural del sistema actual a través de las opciones de región y idioma del panel de control. Por ejemplo, los usuarios pueden elegir un símbolo de moneda diferente o un símbolo separador decimal diferente. Si la propiedad CultureInfo.UseUserOverride se establece en true (su valor predeterminado), las propiedades del objeto NumberFormatInfo también se recuperan de la configuración del usuario.

Todas las propiedades reemplazables por el usuario de un objeto NumberFormatInfo se inicializan cuando se crea el objeto. Todavía existe la posibilidad de incoherencia, ya que ni la creación de objetos ni el proceso de invalidación del usuario son atómicas y los valores pertinentes pueden cambiar durante la creación de objetos. Sin embargo, estas incoherencias deben ser extremadamente raras.

Puede controlar si las invalidaciones de usuario se reflejan en objetos NumberFormatInfo que representan la misma referencia cultural que la referencia cultural actual. En la siguiente tabla se enumeran las formas en que se puede recuperar un objeto NumberFormatInfo e indica si el objeto resultante refleja las invalidaciones del usuario.

Origen del objeto CultureInfo y NumberFormatInfo Refleja las invalidaciones de usuario
PropiedadCultureInfo.CurrentCulture.NumberFormat
PropiedadNumberFormatInfo.CurrentInfo
Método CultureInfo.CreateSpecificCulture
Método CultureInfo.GetCultureInfo No
Constructor CultureInfo(String)
Constructor CultureInfo.CultureInfo(String, Boolean) Depende del valor del parámetro useUserOverride

A menos que haya una razón convincente para hacerlo, debe respetar las invalidaciones del usuario al usar el objeto NumberFormatInfo en las aplicaciones cliente para dar formato y analizar la entrada del usuario o mostrar datos numéricos. En el caso de las aplicaciones de servidor o las aplicaciones desatendidas, no debe respetar las invalidaciones de usuario. Sin embargo, si usa el objeto NumberFormatInfo explícita o implícitamente para conservar datos numéricos en forma de cadena, debe usar un objeto NumberFormatInfo que refleje las convenciones de formato de la referencia cultural invariable o debe especificar una cadena de formato numérico personalizada que use independientemente de la referencia cultural.

IFormatProvider, NumberFormatInfo y formato numérico

Un objeto NumberFormatInfo se usa implícita o explícitamente en todas las operaciones de formato numérico. Estas incluyen llamadas a los métodos siguientes:

Todas las operaciones de formato numérico usan una implementación IFormatProvider. La interfaz IFormatProvider incluye un único método, GetFormat(Type). Se trata de un método de devolución de llamada que se pasa a un objeto Type que representa el tipo necesario para proporcionar información de formato. El método es responsable de devolver una instancia de ese tipo o null, si no puede proporcionar una instancia del tipo. .NET proporciona dos implementaciones IFormatProvider para dar formato a los números:

Si no se proporciona explícitamente una implementación IFormatProvider a un método de formato, se usa un objeto CultureInfo devuelto por la propiedad CultureInfo.CurrentCulture que representa la referencia cultural actual.

En el ejemplo siguiente se muestra la relación entre la interfaz IFormatProvider y la clase NumberFormatInfo en las operaciones de formato mediante la definición de una implementación personalizada IFormatProvider. Su método GetFormat muestra el nombre de tipo del objeto solicitado por la operación de formato. Si la interfaz solicita un objeto NumberFormatInfo, este método proporciona el objeto NumberFormatInfo para la referencia cultural actual. Como se muestra en la salida del ejemplo, el método Decimal.ToString(IFormatProvider) solicita un objeto NumberFormatInfo para proporcionar información de formato, mientras que el método String.Format(IFormatProvider, String, Object[]) solicita objetos NumberFormatInfo y DateTimeFormatInfo, así como una implementación ICustomFormatter.

using System;
using System.Globalization;

public class CurrentCultureFormatProvider : IFormatProvider
{
    public Object GetFormat(Type formatType)
    {
        Console.WriteLine("Requesting an object of type {0}",
                          formatType.Name);
        if (formatType == typeof(NumberFormatInfo))
            return NumberFormatInfo.CurrentInfo;
        else if (formatType == typeof(DateTimeFormatInfo))
            return DateTimeFormatInfo.CurrentInfo;
        else
            return null;
    }
}

public class FormatProviderEx
{
    public static void Main()
    {
        Decimal amount = 1203.541m;
        string value = amount.ToString("C2", new CurrentCultureFormatProvider());
        Console.WriteLine(value);
        Console.WriteLine();
        string composite = String.Format(new CurrentCultureFormatProvider(),
                                         "Date: {0}   Amount: {1}   Description: {2}",
                                         DateTime.Now, 1264.03m, "Service Charge");
        Console.WriteLine(composite);
        Console.WriteLine();
    }
}
// The example displays output like the following:
//    Requesting an object of type NumberFormatInfo
//    $1,203.54
//
//    Requesting an object of type ICustomFormatter
//    Requesting an object of type DateTimeFormatInfo
//    Requesting an object of type NumberFormatInfo
//    Date: 11/15/2012 2:00:01 PM   Amount: 1264.03   Description: Service Charge

Si una implementación IFormatProvider no se proporciona explícitamente en una llamada al método de formato numérico, el método llama al método CultureInfo.CurrentCulture.GetFormat, que devuelve el objetoNumberFormatInfo que corresponde a la referencia cultural actual.

Formato de cadenas y propiedades NumberFormatInfo

Cada operación de formato usa una cadena de formato numérico estándar o personalizada para generar una cadena de resultado a partir de un número. En algunos casos, el uso de una cadena de formato para generar una cadena de resultado es explícito, como en el ejemplo siguiente. Este código llama al método Decimal.ToString(IFormatProvider) para convertir un valor Decimal en una serie de representaciones de cadena diferentes mediante las convenciones de formato de la referencia cultural en-US.

using System;
using System.Globalization;

public class PropertiesEx1
{
    public static void Main()
    {
        string[] formatStrings = { "C2", "E1", "F", "G3", "N",
                                 "#,##0.000", "0,000,000,000.0##" };
        CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
        Decimal[] values = { 1345.6538m, 1921651.16m };

        foreach (var value in values)
        {
            foreach (var formatString in formatStrings)
            {
                string resultString = value.ToString(formatString, culture);
                Console.WriteLine("{0,-18} -->  {1}", formatString, resultString);
            }
            Console.WriteLine();
        }
    }
}
// The example displays the following output:
//       C2                 -->  $1,345.65
//       E1                 -->  1.3E+003
//       F                  -->  1345.65
//       G3                 -->  1.35E+03
//       N                  -->  1,345.65
//       #,##0.000          -->  1,345.654
//       0,000,000,000.0##  -->  0,000,001,345.654
//
//       C2                 -->  $1,921,651.16
//       E1                 -->  1.9E+006
//       F                  -->  1921651.16
//       G3                 -->  1.92E+06
//       N                  -->  1,921,651.16
//       #,##0.000          -->  1,921,651.160
//       0,000,000,000.0##  -->  0,001,921,651.16

En otros casos, el uso de una cadena de formato es implícito. Por ejemplo, en el método siguiente se llama al método Decimal.ToString() predeterminado o sin parámetros, el valor de la instancia Decimal tiene formato mediante el especificador de formato general ("G") y las convenciones de la referencia cultural actual, que en este caso es la referencia cultural en-US.

using System;

public class PropertiesEx2
{
    public static void Main()
    {
        Decimal[] values = { 1345.6538m, 1921651.16m };

        foreach (var value in values)
        {
            string resultString = value.ToString();
            Console.WriteLine(resultString);
            Console.WriteLine();
        }
    }
}
// The example displays the following output:
//       1345.6538
//
//       1921651.16

Cada cadena de formato numérico estándar usa una o varias propiedades NumberFormatInfo para determinar el patrón o los símbolos usados en la cadena de resultado. Del mismo modo, cada especificador de formato numérico personalizado excepto "0" y "#" inserta símbolos en la cadena de resultado definida por NumberFormatInfo las propiedades. En la tabla siguiente se enumeran los especificadores de formato numérico estándar y personalizado y sus propiedades asociadas NumberFormatInfo. Para cambiar la apariencia de la cadena de resultado de una referencia cultural determinada, consulte la sección Modificar propiedades NumberFormatInfo. Para obtener más información acerca del uso de estos especificadores de formato, consulte Cadenas de formato numérico estándar y Cadenas de formato numérico personalizado.

Especificador de formato Propiedades asociadas
"C" o "c" (especificador de formato de moneda) CurrencyDecimalDigits, para definir el número predeterminado de dígitos fraccionarios.

CurrencyDecimalSeparator, para definir el símbolo separador decimal.

CurrencyGroupSeparator, para definir el separador de grupos o miles.

CurrencyGroupSizes, para definir los tamaños de los grupos enteros.

CurrencyNegativePattern, para definir el patrón de valores de moneda negativos.

CurrencyPositivePattern, para definir el patrón de valores de moneda positivos.

CurrencySymbol, para definir el símbolo de moneda.

NegativeSign, para definir el símbolo de signo negativo.
"D" o "d" (especificador de formato decimal) NegativeSign, para definir el símbolo de signo negativo.
"E" o "e" (especificador de formato exponencial o científico) NegativeSign, para definir el símbolo de signo negativo en la mantisa y el exponente.

NumberDecimalSeparator, para definir el símbolo separador decimal.

PositiveSign, para definir el símbolo de signo positivo en el exponente.
"F" o "f" (especificador de formato de punto fijo) NegativeSign, para definir el símbolo de signo negativo.

NumberDecimalDigits, para definir el número predeterminado de dígitos fraccionarios.

NumberDecimalSeparator, para definir el símbolo separador decimal.
"G" o "g" (especificador de formato general) NegativeSign, para definir el símbolo de signo negativo.

NumberDecimalSeparator, para definir el símbolo separador decimal.

PositiveSign, para definir el símbolo de signo positivo para las cadenas de resultado en formato exponencial.
"N" o "n" (especificador de formato de número) NegativeSign, para definir el símbolo de signo negativo.

NumberDecimalDigits, para definir el número predeterminado de dígitos fraccionarios.

NumberDecimalSeparator, para definir el símbolo separador decimal.

NumberGroupSeparator, para definir el símbolo separador de grupo (miles).

NumberGroupSizes, para definir el número de dígitos enteros en un grupo.

NumberNegativePattern, para definir el formato de los valores negativos.
"P" o "p" (especificador de formato de porcentaje) NegativeSign, para definir el símbolo de signo negativo.

PercentDecimalDigits, para definir el número predeterminado de dígitos fraccionarios.

PercentDecimalSeparator, para definir el símbolo separador decimal.

PercentGroupSeparator, para definir el símbolo separador de grupo.

PercentGroupSizes, para definir el número de dígitos enteros en un grupo.

PercentNegativePattern, para definir la ubicación del símbolo de porcentaje y el símbolo negativo para los valores negativos.

PercentPositivePattern, para definir la ubicación del símbolo de porcentaje para los valores positivos.

PercentSymbol, para definir el símbolo de porcentaje.
"R" o "r" (especificador de formato de ida y vuelta) NegativeSign, para definir el símbolo de signo negativo.

NumberDecimalSeparator, para definir el símbolo separador decimal.

PositiveSign, para definir el símbolo de signo positivo en un exponente.
"X" o "x" (especificador de formato hexadecimal) Ninguno.
"." (especificador de formato personalizado de punto decimal) NumberDecimalSeparator, para definir el símbolo separador decimal.
"," (especificador de formato personalizado separador de grupo) NumberGroupSeparator, para definir el símbolo separador de grupo (miles).
"%" (especificador de formato personalizado de marcador de posición de porcentaje) PercentSymbol, para definir el símbolo de porcentaje.
"‰" (especificador de formato personalizado de marcador de posición por mil) PerMilleSymbol, para definir el símbolo por mil.
"E" (especificador de formato personalizado de notación exponencial) NegativeSign, para definir el símbolo de signo negativo en la mantisa y el exponente.

PositiveSign, para definir el símbolo de signo positivo en el exponente.

Tenga en cuenta que la clase NumberFormatInfo incluye una propiedad NativeDigits que especifica los 10 dígitos base utilizados por una referencia cultural específica. Sin embargo, la propiedad no se usa en las operaciones de formato; solo se usan los dígitos latinos básicos 0 (U+0030) a 9 (U+0039) en la cadena de resultado. Además, para los valores Single y Double de NaN, PositiveInfinity, y NegativeInfinity, la cadena de resultado consta exclusivamente de los símbolos definidos por las propiedades NaNSymbol, PositiveInfinitySymbol, y NegativeInfinitySymbol respectivamente.

Modificar las propiedades NumberFormatInfo

Puede modificar las propiedades de un objeto NumberFormatInfo para personalizar la cadena de resultado generada en una operación de formato numérico. Para ello, siga estos pasos:

  1. Cree una copia de lectura y escritura de un objeto NumberFormatInfo cuyas convenciones de formato quiera modificar. Para obtener más información, consulte la sección Creación de instancias de un objeto NumberFormatInfo.

  2. Modifique la propiedad o las propiedades que se usan para generar la cadena de resultado deseada. Para obtener información acerca de cómo los métodos de formato usan NumberFormatInfo propiedades para definir cadenas de resultado, consulte la sección Formato de cadenas y propiedades NumberFormatInfo.

  3. Use el objeto personalizado NumberFormatInfo como argumento IFormatProvider en llamadas a métodos de formato.

Nota:

En lugar de modificar dinámicamente los valores de propiedad de una referencia cultural cada vez que se inicia una aplicación, puede usar la clase CultureAndRegionInfoBuilder para definir una referencia cultural personalizada (una referencia cultural que tiene un nombre único y que complementa las referencias culturales existentes) o una referencia cultural de reemplazo (una que se usa en lugar de una referencia cultural específica).

En las secciones siguientes se proporcionan algunos ejemplos.

Modificar el símbolo de moneda y el patrón

En el ejemplo siguiente se modifica un objeto NumberFormatInfo que representa las convenciones de formato de la referencia cultural en-US. Asigna el símbolo de moneda ISO-4217 a la propiedad CurrencySymbol y define un patrón para los valores de moneda que constan del símbolo de moneda seguido de un espacio y un valor numérico.

using System;
using System.Globalization;

public class Example
{
    public static void Main()
    {
        // Retrieve a writable NumberFormatInfo object.
        CultureInfo enUS = CultureInfo.CreateSpecificCulture("en-US");
        NumberFormatInfo nfi = enUS.NumberFormat;

        // Use the ISO currency symbol instead of the native currency symbol.
        nfi.CurrencySymbol = (new RegionInfo(enUS.Name)).ISOCurrencySymbol;
        // Change the positive currency pattern to <code><space><value>.
        nfi.CurrencyPositivePattern = 2;
        // Change the negative currency pattern to <code><space><sign><value>.
        nfi.CurrencyNegativePattern = 12;

        // Produce the result strings by calling ToString.
        Decimal[] values = { 1065.23m, 19.89m, -.03m, -175902.32m };
        foreach (var value in values)
            Console.WriteLine(value.ToString("C", enUS));

        Console.WriteLine();

        // Produce the result strings by calling a composite formatting method.
        foreach (var value in values)
            Console.WriteLine(String.Format(enUS, "{0:C}", value));
    }
}
// The example displays the following output:
//       USD 1,065.23
//       USD 19.89
//       USD -0.03
//       USD -175,902.32
//
//       USD 1,065.23
//       USD 19.89
//       USD -0.03
//       USD -175,902.32

Dar formato a un número de identificación nacional

Muchos números de identificación nacional constan exclusivamente de dígitos, por lo que se pueden formatear fácilmente modificando las propiedades de un objeto NumberFormatInfo. Por ejemplo, un número del seguro social de Los Estados Unidos consta de 9 dígitos organizados de la siguiente manera: XXX-XX-XXXX. En el ejemplo siguiente se supone que los números de seguridad social se almacenan como valores enteros y los da formato de forma adecuada.

using System;
using System.Globalization;

public class CustomizeSSNEx
{
    public static void Main()
    {
        // Instantiate a read-only NumberFormatInfo object.
        CultureInfo enUS = CultureInfo.CreateSpecificCulture("en-US");
        NumberFormatInfo nfi = enUS.NumberFormat;

        // Modify the relevant properties.
        nfi.NumberGroupSeparator = "-";
        nfi.NumberGroupSizes = new int[] { 3, 2, 4 };
        nfi.NumberDecimalDigits = 0;

        int[] ids = { 111223333, 999776666 };

        // Produce the result string by calling ToString.
        foreach (var id in ids)
            Console.WriteLine(id.ToString("N", enUS));

        Console.WriteLine();

        // Produce the result string using composite formatting.
        foreach (var id in ids)
            Console.WriteLine(String.Format(enUS, "{0:N}", id));
    }
}
// The example displays the following output:
//       1112-23-333
//       9997-76-666
//
//       1112-23-333
//       9997-76-666

Análisis de cadenas numéricas

El análisis implica convertir la representación de cadena de un número en un número. Cada tipo numérico de .NET incluye dos métodos de análisis sobrecargados: Parse y TryParse. El método Parse convierte una cadena en un número y produce una excepción si se produce un error en la conversión. El método TryParse convierte una cadena en un número, asigna el número a un argumento out y devuelve un valor Boolean que indica si la conversión se ha realizado correctamente.

Los métodos de análisis usan implícita o explícitamente un valor de enumeración NumberStyles para determinar qué elementos de estilo (como separadores de grupo, separadores decimales o símbolos de moneda) pueden estar presentes en una cadena si la operación de análisis es correcta. Si no se proporciona un valor en la llamada al método NumberStyles, el valor predeterminado es un valor NumberStyles que incluye las marcas Float y AllowThousands, que especifica que la cadena analizada puede incluir símbolos de grupo, un separador decimal, un signo negativo y caracteres de espacio en blanco, o puede ser la representación de cadena de un número en notación exponencial.

Los métodos de análisis también usan implícita o explícitamente un objeto NumberFormatInfo que define los símbolos y patrones específicos que pueden producirse en la cadena que se van a analizar. Si no se proporciona un objeto NumberFormatInfo, el valor predeterminado es para NumberFormatInfo la referencia cultural actual. Para obtener más información acerca del análisis, consulte los métodos de análisis individuales, como Int16.Parse(String), Int32.Parse(String, NumberStyles), Int64.Parse(String, IFormatProvider), Decimal.Parse(String, NumberStyles, IFormatProvider), Double.TryParse(String, Double), y BigInteger.TryParse(String, NumberStyles, IFormatProvider, BigInteger).

En el ejemplo siguiente se muestra la naturaleza que distingue la referencia cultural de las cadenas de análisis. Intenta analizar una cadena que incluya separadores de miles mediante las convenciones de las referencias culturales en-US, fr-FR e invariables. Una cadena que incluye la coma como separador de grupo y el punto como separador decimal no se puede analizar en la referencia cultural fr-FR y una cadena con espacio en blanco como separador de grupo y una coma como separador decimal no se puede analizar en las referencias culturales en-US y invariables.

using System;
using System.Globalization;

public class ParseEx1
{
    public static void Main()
    {
        String[] values = { "1,034,562.91", "9 532 978,07" };
        String[] cultureNames = { "en-US", "fr-FR", "" };

        foreach (var value in values)
        {
            foreach (var cultureName in cultureNames)
            {
                CultureInfo culture = CultureInfo.CreateSpecificCulture(cultureName);
                String name = culture.Name == "" ? "Invariant" : culture.Name;
                try
                {
                    Decimal amount = Decimal.Parse(value, culture);
                    Console.WriteLine("'{0}' --> {1} ({2})", value, amount, name);
                }
                catch (FormatException)
                {
                    Console.WriteLine("'{0}': FormatException ({1})",
                                      value, name);
                }
            }
            Console.WriteLine();
        }
    }
}
// The example displays the following output:
//       '1,034,562.91' --> 1034562.91 (en-US)
//       '1,034,562.91': FormatException (fr-FR)
//       '1,034,562.91' --> 1034562.91 (Invariant)
//
//       '9 532 978,07': FormatException (en-US)
//       '9 532 978,07' --> 9532978.07 (fr-FR)
//       '9 532 978,07': FormatException (Invariant)

El análisis generalmente se produce en dos contextos:

  • Como una operación diseñada para convertir la entrada del usuario en un valor numérico.

  • Como una operación diseñada para realizar un recorrido de ida y vuelta un valor numérico; es decir, para deserializar un valor numérico que se serializó previamente como una cadena.

En las siguientes secciones se describen estas dos operaciones con mayor detalle.

Análisis de cadenas de usuario

Al analizar las cadenas numéricas de entrada por el usuario, siempre debe crear una instancia de un objeto NumberFormatInfo que refleje la configuración cultural del usuario. Para obtener información acerca de cómo crear instancias de un objeto NumberFormatInfo que refleje las personalizaciones del usuario, consulte la sección Datos dinámicos.

En el siguiente ejemplo se muestra la diferencia entre una operación de análisis que refleja la configuración cultural del usuario y otra que no lo hace. En este caso, la referencia cultural del sistema predeterminada es en-US, pero el usuario ha definido "," como símbolo decimal y "." como separador de grupo en el Panel de control, Región e idioma. Normalmente, estos símbolos se invierten en la referencia cultural predeterminada en-US. Cuando el usuario escribe una cadena que refleja la configuración del usuario y la cadena se analiza mediante un objeto NumberFormatInfo que también refleja la configuración del usuario (invalidaciones), la operación de análisis devuelve un resultado correcto. Sin embargo, cuando un objeto NumberFormatInfo analiza la cadena que refleja la configuración cultural estándar en-US, se equivoca el símbolo de coma de un separador de grupo y devuelve un resultado incorrecto.

using System;
using System.Globalization;

public class ParseUserEx
{
    public static void Main()
    {
        CultureInfo stdCulture = CultureInfo.GetCultureInfo("en-US");
        CultureInfo custCulture = CultureInfo.CreateSpecificCulture("en-US");

        String value = "310,16";
        try
        {
            Console.WriteLine("{0} culture reflects user overrides: {1}",
                              stdCulture.Name, stdCulture.UseUserOverride);
            Decimal amount = Decimal.Parse(value, stdCulture);
            Console.WriteLine("'{0}' --> {1}", value, amount.ToString(CultureInfo.InvariantCulture));
        }
        catch (FormatException)
        {
            Console.WriteLine("Unable to parse '{0}'", value);
        }
        Console.WriteLine();

        try
        {
            Console.WriteLine("{0} culture reflects user overrides: {1}",
                              custCulture.Name, custCulture.UseUserOverride);
            Decimal amount = Decimal.Parse(value, custCulture);
            Console.WriteLine("'{0}' --> {1}", value, amount.ToString(CultureInfo.InvariantCulture));
        }
        catch (FormatException)
        {
            Console.WriteLine("Unable to parse '{0}'", value);
        }
    }
}
// The example displays the following output:
//       en-US culture reflects user overrides: False
//       '310,16' --> 31016
//
//       en-US culture reflects user overrides: True
//       '310,16' --> 310.16

Serialización y deserialización de datos numéricos

Cuando los datos numéricos se serializan en formato de cadena y posteriormente se deserializan y analizan, las cadenas se deben generar y analizar mediante las convenciones de la referencia cultural invariable. Las operaciones de formato y análisis nunca deben reflejar las convenciones de una referencia cultural específica. Si se usa una configuración específica de la referencia cultural, la portabilidad de los datos es estrictamente limitada; solo se puede deserializar correctamente en un subproceso cuya configuración específica de la referencia cultural es idéntica a la del subproceso en el que se ha serializado. En algunos casos, esto significa que los datos ni siquiera se pueden deserializar correctamente en el mismo sistema en el que se ha serializado.

En el ejemplo siguiente se muestra lo que puede ocurrir cuando se infringe este principio. Los valores de punto flotante de una matriz se convierten en cadenas cuando el subproceso actual usa la configuración específica de la referencia cultural en-US. A continuación, los datos se analizan mediante un subproceso que usa la configuración específica de la referencia cultural pt-BR. En este caso, aunque cada operación de análisis se realiza correctamente, los datos no se realizan correctamente y se producen daños en los datos. En otros casos, se podría producir un error en una operación de análisis y se podría producir una excepción FormatException.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;

public class ParsePersistedEx
{
    public static void Main()
    {
        CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
        PersistData();

        CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture("pt-BR");
        RestoreData();
    }

    private static void PersistData()
    {
        // Define an array of floating-point values.
        Double[] values = { 160325.972, 8631.16, 1.304e5, 98017554.385,
                          8.5938287084321676e94 };
        Console.WriteLine("Original values: ");
        foreach (var value in values)
            Console.WriteLine(value.ToString("R", CultureInfo.InvariantCulture));

        // Serialize an array of doubles to a file
        StreamWriter sw = new StreamWriter(@".\NumericData.bin");
        for (int ctr = 0; ctr < values.Length; ctr++)
        {
            sw.Write(values[ctr].ToString("R"));
            if (ctr < values.Length - 1) sw.Write("|");
        }
        sw.Close();
        Console.WriteLine();
    }

    private static void RestoreData()
    {
        // Deserialize the data
        StreamReader sr = new StreamReader(@".\NumericData.bin");
        String data = sr.ReadToEnd();
        sr.Close();

        String[] stringValues = data.Split('|');
        List<Double> newValueList = new List<Double>();

        foreach (var stringValue in stringValues)
        {
            try
            {
                newValueList.Add(Double.Parse(stringValue));
            }
            catch (FormatException)
            {
                newValueList.Add(Double.NaN);
            }
        }

        Console.WriteLine("Restored values:");
        foreach (var newValue in newValueList)
            Console.WriteLine(newValue.ToString("R", NumberFormatInfo.InvariantInfo));
    }
}
// The example displays the following output:
//       Original values:
//       160325.972
//       8631.16
//       130400
//       98017554.385
//       8.5938287084321671E+94
//
//       Restored values:
//       160325972
//       863116
//       130400
//       98017554385
//       8.5938287084321666E+110