2009-11-08 3 views
30

Quelle est la différence et la connexion entre IFormattable, IFormatProvider et ICustomFormatter et quand seraient-ils utilisés? Un exemple d'implémentation simple serait très bien aussi. Je ne veux pas vraiment dire quand il est utilisé dans le framework .net, mais quand je les implémenterais moi-même et dans ce cas quelles classes implémenteraient typiquement quelle interface et comment le faire correctement.C#: Connexion entre IFormattable, IFormatProvider et ICustomFormatter, et quand utiliser

Répondre

32
  • IFormattable est un objet qui prend en charge les formats string.Format, à savoir le xxx dans {0:xxx}. string.Format va déléguer à la méthode IFormattable.ToString si l'objet prend en charge l'interface.

  • IFormatProvider est une source d'informations de configuration que les formateurs utilisent pour des éléments tels que la mise en page de date et de devise spécifique à la culture.

  • Cependant, pour des situations telles que par ex. DateTime, où l'instance que vous souhaitez mettre en œuvre implémente déjà IFormattable mais vous ne contrôlez pas l'implémentation (DateTime est fourni dans le BCL, vous ne pouvez pas le remplacer facilement), il existe un mécanisme pour empêcher string.Format d'utiliser simplement IFormattable.ToString. Au lieu de cela, vous implémentez IFormatProvider et lorsque vous demandez une implémentation ICustomFormatter, renvoyez-en une. string.Format vérifie le fournisseur pour un ICustomFormatter avant de déléguer à IFormattable.Format de l'objet, ce qui à son tour demanderait probablement le IFormatProvider pour des données spécifiques à la culture comme CultureInfo.

Voici un programme qui montre ce string.Format demande au IFormatProvider, et comment le flux de contrôle va:

using System; 
using System.Globalization; 

class MyCustomObject : IFormattable 
{ 
    public string ToString(string format, IFormatProvider provider) 
    { 
     Console.WriteLine("ToString(\"{0}\", provider) called", format); 
     return "arbitrary value"; 
    } 
} 

class MyFormatProvider : IFormatProvider 
{ 
    public object GetFormat(Type formatType) 
    { 
     Console.WriteLine("Asked for {0}", formatType); 
     return CultureInfo.CurrentCulture.GetFormat(formatType); 
    } 
} 

class App 
{ 
    static void Main() 
    { 
     Console.WriteLine(
      string.Format(new MyFormatProvider(), "{0:foobar}", 
       new MyCustomObject())); 
    } 
} 

Il imprime ceci:

Asked for System.ICustomFormatter 
ToString("foobar", provider) called 
arbitrary value 

Si le fournisseur de format est modifié pour retourner un formateur personnalisé, il prend en charge:

class MyFormatProvider : IFormatProvider 
{ 
    public object GetFormat(Type formatType) 
    { 
     Console.WriteLine("Asked for {0}", formatType); 
     if (formatType == typeof(ICustomFormatter)) 
      return new MyCustomFormatter(); 
     return CultureInfo.CurrentCulture.GetFormat(formatType); 
    } 
} 

class MyCustomFormatter : ICustomFormatter 
{ 
    public string Format(string format, object arg, IFormatProvider provider) 
    { 
     return string.Format("(format was \"{0}\")", format); 
    } 
} 

Quand course:

Asked for System.ICustomFormatter 
(format was "foobar") 
+0

Pourquoi renvoyez-vous 'CultureInfo.CurrentCulture.GetFormat' dans' MyFormatProvider.GetFormat'? Et que voulez-vous utiliser le 'IFormatProvider' dans' MyCustomFormatter.Format'? – Svish

+0

Le fournisseur de format par défaut est CultureInfo.CurrentCulture; c'est celui qui est utilisé si vous n'en spécifiez pas un dans l'une des surcharges de 'string.Format'. J'ai déjà expliqué ce que vous utiliseriez pour IFormatProvider - pour fournir des informations de configuration (par exemple demander CultureInfo), pour des choses comme le formatage de date (par exemple pour utiliser CultureInfo.DateTimeFormat). –

1

IFormattable est un objet qui prend en charge différents formats (nommés/personnalisés) - par exemple, les nombres, etc. En utilisant une interface, plusieurs blocs de code peuvent utiliser la valeur et une chaîne de format, ce qui est commun) dans la liaison de données et string.Format.

Un IFormatProvider comble certaines lacunes en matière de formatage - en particulier i18n. Le plus souvent, un CultureInfo est utilisé comme fournisseur, soit en donnant un format local spécifique, soit la culture invariante. Pour autant que je sache, ICustomFormatter est sans rapport, et lie plus en sérialisation (BinaryFormatter). Je peux me tromper ...

Un exemple d'un objet IFormattable:

IFormattable d = 123.45M; 
string s1 = d.ToString("c", CultureInfo.CurrentCulture), // local currency 
     s2 = d.ToString("c", CultureInfo.InvariantCulture); // invariant currency 
+2

Ceci est une réponse très ancienne, mais pour le bien des enfants: 'ICustomFormatter' est en effet sur le formatage de chaîne, et pour ajouter le support pour les chaînes de format à des types qui ne sont pas' Implémentations IFormattable (ou pour fournir différentes chaînes de format aux objets IFormattable). 'IFormatter' est celui sur la sérialisation. –

Questions connexes