2010-03-04 15 views
19

Estaba intentando crear una implementación IFormatProvider que reconocería cadenas de formato personalizado para objetos DateTime. Aquí está mi aplicación:Cómo crear y usar un IFormatProvider personalizado para DateTime?

public class MyDateFormatProvider : IFormatProvider, ICustomFormatter 
{ 
    public object GetFormat(Type formatType) 
    { 
    if (formatType == typeof(ICustomFormatter)) 
    { 
    return this; 
    } 
    return null; 
    } 

    public string Format(string format, object arg, IFormatProvider formatProvider) 
    { 
    if(arg == null) throw new ArgumentNullException("arg"); 
    if (arg.GetType() != typeof(DateTime)) return arg.ToString(); 
    DateTime date = (DateTime)arg; 
    switch(format) 
    { 
    case "mycustomformat": 
    switch(CultureInfo.CurrentCulture.Name) 
    { 
     case "en-GB": 
     return date.ToString("ddd dd MMM"); 
     default: 
     return date.ToString("ddd MMM dd"); 
    } 
    default: 
    throw new FormatException(); 
    } 
    } 

que estaba esperando para poder utilizarla en el método DateTime.ToString(string format, IFormatProvider provider) como tal, sino:

DateTime d = new DateTime(2000, 1, 2); 
string s = d.ToString("mycustomformat", new MyDateFormatProvider()); 

En ese ejemplo, se ejecuta en la cultura de Estados Unidos, el resultado es "00cu0Ao00or0aA", al parecer porque las cadenas de formato de fecha y hora estándar se están interpretando.

Sin embargo, cuando se utiliza la misma clase de la siguiente manera:

DateTime d = new DateTime(2000, 1, 2); 
string s = String.Format(new MyDateFormatProvider(), "{0:mycustomformat}", d); 

consigo lo que esperaba, a saber "Sun Jan 02"

que no entienden los diferentes resultados. ¿Alguien podría explicar?

Gracias!

Respuesta

9

La comprobación del método DateTime.ToString con Reflector muestra que la estructura DateTime utiliza el método DateTimeFormatInfo.GetInstance para hacer que el proveedor se utilice para formatear. El DateTimeFormatInfo.GetInstance solicita un formateador de tipo DateTimeFormatInfo del proveedor que se transfiere, nunca para ICustomFormmater, por lo que solo devuelve una instancia de DateTimeFormatInfo o CultureInfo si no se encuentra ningún proveedor. Parece que el método DateTime.ToString no respeta la interfaz ICustomFormatter como lo hace el método StringBuilder.Format, como muestra su ejemplo String.Format.

Acepto que el método DateTime.ToString debe admitir la interfaz ICustomFormatter, pero no parece actualmente. Esto puede haber cambiado o cambiará en .NET 4.0.

+0

Gracias por la respuesta detallada. Estaba pensando que estaba malinterpretando la interfaz y la implementación esperada, por lo que es bueno saber que es la implementación de DateTime lo que es raro :-) –

3

método de uso extensión :)

public static class FormatProviderExtension 
    { 
     public static string FormatIt(string format, object arg, IFormatProvider formatProvider) 
     { 
      if (arg == null) throw new ArgumentNullException("arg"); 
      if (arg.GetType() != typeof(DateTime)) return arg.ToString(); 
      DateTime date = (DateTime)arg; 
      switch (format) 
      { 
       case "mycustomformat": 
        switch (CultureInfo.CurrentCulture.Name) 
        { 
         case "en-GB": 
          return date.ToString("ddd dd MMM"); 
         default: 
          return date.ToString("ddd MMM dd"); 
        } 
       default: 
        throw new FormatException(); 
      } 
     } 

     public static string ToString(this DateTime d, IFormatProvider formatProvider, string format) 
     { 
      return FormatIt(format, d, formatProvider); 
     } 
    } 
+0

Sí, parece que los métodos de extensión son mi única opción aquí. ¡Gracias por la respuesta! –

17

La breve explicación es que mientras

DateTime.ToString(string format, IFormatProvider provider) 

deja que pase nada implementación IFormatProvider como uno de sus parámetros, que en realidad sólo admite 2 tipos posibles de aplicación IFormatProvider dentro de su código:

DateTimeFormatInfo o CultureInfo

Si su parámetro no se puede convertir (usando as) como uno o más, el método predeterminado será CurrentCulture.

String.Format no está limitado por tales límites.

Cuestiones relacionadas