Personalizar cadenas de formato

Actualización: noviembre 2007

.NET Framework admite la extensión del mecanismo de formato integrado, de modo que puede crear un método ToString propio que acepte cadenas de formato definidas por el usuario o crear un proveedor de formato que invoque a su propio método Format para aplicar un formato personalizado a un tipo. Puede crear su propio método ToString implementando la interfaz IFormattable, y su propio método Format implementando las interfaces ICustomFormatter e IFormatProvider.

La información de esta sección se limita a agregar cadenas de formato personalizado a tipos definidos por el usuario y a tipos base existentes, pero los principios descritos se pueden aplicar a cualquier tipo.

Agregar cadenas de formato personalizado para los tipos personalizados

Si crea su propio tipo personalizado, puede agregar compatibilidad para procesar sus propias cadenas de formato personalizado mediante la implementación de la interfaz IFormattable y el método ToString de dicha interfaz. Esto significa que se puede controlar qué cadenas de formato reconoce su tipo personalizado. La ventaja de implementar la interfaz IFormattable en lugar de agregar simplemente un método ToString a su tipo personalizado es que puede garantizar a los usuarios de su método ToString una sintaxis de llamada predefinida y un tipo de valor devuelto.

El método ToString de la interfaz IFormattable toma un parámetro de cadena de formato y un parámetro de proveedor de formato. Si el valor del parámetro de cadena de formato es una cadena vacía o null (Nothing en Visual Basic), aplique un formato predeterminado. Si el valor del proveedor de formato es null, utilice un proveedor de formato predeterminado.

Si se pasa una cadena de formato personalizado a la versión personalizada de ToString, aplique el formato adecuado; de lo contrario, llame a un método de .NET Framework apropiado para aplicar un formato estándar.

En el siguiente ejemplo, el tipo personalizado MyType implementa la interfaz IFormattable. Si crea una nueva instancia de la clase MyType y pasa la cadena de formato personalizado "b" al método ToString de la instancia, una sobrecarga de Convert.ToString devuelve la representación de cadena binaria (base 2) del valor de la instancia. Si no se pasa "b", se aplica formato al valor de la instancia con el método ToString propio; es decir, se da formato al entero myValue mediante el método System.Int32.ToString.

Public Class MyType
    Implements IFormattable
    ' Assign a value for the class.
    Private myValue As Integer    

    ' Add a constructor.
    Public Sub New(value As Integer)
        myValue = value
    End Sub

    ' Write a custom Format method for the type.
    Public Overloads Function ToString(format As String, _
                                       fp As IFormatProvider) As String _
                              Implements IFormattable.ToString

        If format.Equals("b") Then
            Return Convert.ToString(myValue, 2)
        Else
            Return myValue.ToString(format, fp)
        End If
    End Function
End Class
public class MyType : IFormattable
{
    // Assign a value for the class.
    private int myValue;

    // Add a constructor.
    public MyType( int value )
    {
        myValue = value;
    }
    // Write a custom Format method for the type.
    public string ToString(string format, IFormatProvider fp)
    {
        if (format.Equals ("b"))
            {
            return Convert.ToString (myValue, 2);
            }
        else
            {
            return myValue.ToString(format, fp);
            }
    }
}

En el ejemplo siguiente se muestra cómo se utilizan la clase MyType y la cadena de formato "b".

Dim mtype As New MyType(42)
Dim myString As String = mtype.ToString("b", Nothing)
Dim yourString As String = mtype.ToString("d", Nothing)
Console.WriteLine(myString)
Console.WriteLine(yourString)
' The example produces the following output:
'       101010
'       42
MyType mtype = new MyType(42);
String myString = mtype.ToString("b", null);
String yourString = mtype.ToString("d", null);
Console.WriteLine(myString);
Console.WriteLine(yourString);
// The example produces the following output:
//       101010
//       42

Agregar cadenas de formato personalizado a tipos existentes

Mediante la creación de una clase de proveedor de formato que implemente ICustomFormatter y IformatProvider, se puede controlar cómo se aplica el formato a un tipo base existente, y proporcionar códigos adicionales de formato.

Cuando se pasa un proveedor de formato al método ToString de un tipo base, el tipo base utiliza el proveedor de formato que se ha pasado para definir las reglas de aplicación de formato, antes que recurrir al proveedor de formato predeterminado. Para crear un proveedor de formato personalizado, hay que hacer lo siguiente:

  1. Definir una clase que implemente las dos interfaces mencionadas anteriormente e invalidar GetFormat y Format.

  2. Pasar esa clase a un método (como String.Format) que toma como parámetro IFormatProvider. Al hacer esto, String.Format reconoce el esquema de formato personalizado definido en la nueva clase proveedora de formato.

En el siguiente ejemplo se define una clase que agrega un método Format personalizado que puede producir diferentes valores base de un entero.

Public Class MyFormat
    Implements IFormatProvider
    Implements ICustomFormatter

    ' String.Format calls this method to get an instance of an
    ' ICustomFormatter to handle the formatting.
    Public Function GetFormat(service As Type) As Object _
    Implements IFormatProvider.GetFormat

        If service.ToString() = GetType(ICustomFormatter).ToString() Then
            Return Me
        Else
            Return Nothing
        End If
    End Function

    ' After String.Format gets the ICustomFormatter, it calls this format
    ' method on each argument.
    Public Function Format(theformat As String, arg As Object, _
                           provider As IFormatProvider) As String _
                    Implements ICustomFormatter.Format

        If theformat Is Nothing Then
            Return String.Format("{0}", arg)
        End If
        Dim i As Integer = theformat.Length
            ' If the object to be formatted supports the IFormattable
            ' interface, pass the format specifier to the 
            ' objects ToString method for formatting.
        If Not theformat.StartsWith("B") Then
            ' If the object to be formatted supports the IFormattable
            ' interface, pass the format specifier to the 
            ' objects ToString method for formatting.
            If TypeOf arg Is IFormattable Then
                return CType(arg, IFormattable).ToString(theformat, provider)
            ' If the object does not support IFormattable, 
            ' call the objects ToString method with no additional
            ' formatting. 
            ElseIf (arg Is Nothing) Then
                return arg.ToString()
            End If
        End If
        ' Uses the format string to
        ' form the output string.
        theformat = theformat.Trim(New Char() {"B"c})
        Dim b As Integer = Convert.ToInt32(theformat)
        Return Convert.ToString(CInt(arg), b)
    End Function
End Class
public class MyFormat : IFormatProvider, ICustomFormatter
{
    // String.Format calls this method to get an instance of an
    // ICustomFormatter to handle the formatting.
    public object GetFormat (Type service)
    {
        if (service == typeof (ICustomFormatter))
        {
            return this;
        }
        else
        {
            return null;
        }
    }
    // After String.Format gets the ICustomFormatter, it calls this format
    // method on each argument.
    public string Format(string format, object arg, IFormatProvider provider) 
    {
        if (format == null)
        {
            return String.Format ("{0}", arg);
        }
        // If the format is not a defined custom code,
        // use the formatting support in ToString.
        if (!format.StartsWith("B")) 
        {
            //If the object to be formatted supports the IFormattable
            //interface, pass the format specifier to the 
            //objects ToString method for formatting.
            if (arg is IFormattable) 
            {
                return ((IFormattable)arg).ToString(format, provider);
            } 
            //If the object does not support IFormattable, 
            //call the objects ToString method with no additional
            //formatting. 
            else if (arg != null) 
            {
                return arg.ToString();
            }
        }
        // Uses the format string to
        // form the output string.
        format = format.Trim (new char [] {'B'});
        int b = Convert.ToInt32 (format);
        return Convert.ToString ((int)arg, b);
    }
}

En el siguiente ejemplo, el método Format utiliza el método Format personalizado definido en MyFormat para mostrar la representación en base 16 de MyInt.

Dim myInt As Integer = 42
Dim myString As String = String.Format(New MyFormat(), _
                         "{0} in the custom B16 format is {1:B16}", _
                         New Object() {MyInt, MyInt})
Console.WriteLine(myString)
' The example displays the following output:
'      42 in the custom B16 format is 2a
int MyInt = 42;
string myString = String.Format(new MyFormat(), 
                         "{0} in the custom B16 format is {1:B16}", 
                         new object[] {MyInt, MyInt});
Console.WriteLine(myString);                               
// The example displays the following output: 
//       42 in custom B16 format is 2a

Vea también

Referencia

IFormattable

IFormatProvider

ICustomFormatter

Otros recursos

Aplicar formato a tipos