2010-03-04 5 views
19

J'essayais de créer une implémentation IFormatProvider qui reconnaîtrait les chaînes de format personnalisées pour les objets DateTime. Voici mon implémentation:Comment créer et utiliser un IFormatProvider personnalisé pour 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(); 
    } 
    } 

Je comptais pouvoir l'utiliser dans la méthode DateTime.ToString(string format, IFormatProvider provider) comme si, mais:

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

Dans cet exemple, en cours d'exécution dans la culture des États-Unis, le résultat est "00cu0Ao00or0aA", apparemment parce que les chaînes de format DateTime standard sont interprétées.

Cependant, lorsque j'utilise la même classe de la manière suivante:

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

Je reçois ce que je pense, à savoir "Sun Jan 02"

Je ne comprends pas les différents résultats. Quelqu'un pourrait-il expliquer?

Merci!

Répondre

9

La vérification de la méthode DateTime.ToString avec Reflector montre que la structure DateTime utilise la méthode DateTimeFormatInfo.GetInstance pour que le fournisseur soit utilisé pour le formatage. Le DateTimeFormatInfo.GetInstance demande un formateur de type DateTimeFormatInfo du fournisseur transmis, jamais pour ICustomFormmater, donc il renvoie uniquement une instance d'un DateTimeFormatInfo ou CultureInfo si aucun fournisseur n'est trouvé. Il semble que la méthode DateTime.ToString n'honore pas l'interface ICustomFormatter comme le fait la méthode StringBuilder.Format, comme le montre l'exemple String.Format.

Je suis d'accord que la méthode DateTime.ToString devrait soutenir l'interface ICustomFormatter, mais il ne semble pas actuellement. Cela peut avoir tous changé ou va changer dans .NET 4.0.

+0

Merci pour la réponse détaillée. Je pensais que j'avais mal compris l'interface et l'implémentation attendue, donc c'est bon de savoir que c'est l'implémentation de DateTime qui est loufoque :-) –

3

Utilisez la méthode d'extension :)

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

Oui, on dirait que les méthodes d'extension sont ma seule option ici. Merci pour la réponse! –

17

L'explication courte est que tout

DateTime.ToString(string format, IFormatProvider provider) 

vous laisse passer quoi que ce soit la mise en œuvre IFormatProvider comme l'un de ses paramètres, il prend en charge en fait seulement 2 types possibles de mise en œuvre IFormatProvider à l'intérieur de son code:

DateTimeFormatInfo ou CultureInfo

Si votre paramètre ne peut pas être casté (en utilisant as) comme l'un ou l'autre, la méthode sera CurrentCulture par défaut.

String.Format n'est pas limitée par de telles limites.

Questions connexes