Nachdem ich darüber nachgedacht hatte, wurde mir klar, dass ich mir eigentlich wünschte, dass String.Format() ein IDictionary als Argument nehmen würde, und dass Vorlagen mit Namen statt mit Indizes geschrieben werden könnten.
Bei Stringsubstitutionen mit vielen möglichen Schlüsseln/Werten führen die Indexnummern zu unleserlichen String-Templates - und in manchen Fällen weiß man nicht einmal, welche Elemente welche Nummer haben werden, also habe ich mir die folgende Erweiterung ausgedacht:
https://gist.github.com/896724
Grundsätzlich können Sie damit String-Vorlagen mit Namen anstelle von Zahlen und ein Wörterbuch anstelle eines Arrays verwenden, und Sie haben alle anderen guten Eigenschaften von String.Format(), so dass die Verwendung eines benutzerdefinierten IFormatProvider, wenn nötig, und ermöglicht die Verwendung aller üblichen Formatierung Syntax - Präzision, Länge, etc.
Le site Beispiel im Referenzmaterial für String.Format ist ein großartiges Beispiel dafür, wie Vorlagen mit vielen nummerierten Elementen völlig unleserlich werden - portiert man dieses Beispiel, um diese neue Erweiterungsmethode zu verwenden, erhält man etwas wie dieses:
var replacements = new Dictionary<String, object>()
{
{ "date1", new DateTime(2009, 7, 1) },
{ "hiTime", new TimeSpan(14, 17, 32) },
{ "hiTemp", 62.1m },
{ "loTime", new TimeSpan(3, 16, 10) },
{ "loTemp", 54.8m }
};
var template =
"Temperature on {date1:d}:\n{hiTime,11}: {hiTemp} degrees (hi)\n{loTime,11}: {loTemp} degrees (lo)";
var result = template.Subtitute(replacements);
Wie bereits erwähnt, sollten Sie so etwas nicht verwenden, wenn Ihr Text stark optimiert werden muss. Wenn Sie auf diese Weise Millionen von Zeichenketten in einer Schleife formatieren müssen, kann der Speicher- und Leistungs-Overhead erheblich sein.
Andererseits, wenn Sie darauf bedacht sind, lesbaren, wartbaren Code zu schreiben - und wenn Sie, sagen wir, eine Reihe von Datenbankoperationen durchführen, wird diese Funktion im Großen und Ganzen keinen bedeutenden Overhead hinzufügen.
...
Der Einfachheit halber habe ich versucht, eine Methode hinzuzufügen, die anstelle eines Wörterbuchs ein anonymes Objekt akzeptiert:
public static String Substitute(this String template, object obj)
{
return Substitute(
template,
obj.GetType().GetProperties().ToDictionary(p => p.Name, p => p.GetValue(obj, null))
);
}
Aus irgendeinem Grund funktioniert dies nicht - die Übergabe eines anonymen Objekts wie new { name: "value" }
zu dieser Erweiterungsmethode gibt eine Kompilierzeit-Fehlermeldung, die besagt, dass die beste Übereinstimmung die IDictionary-Version dieser Methode war. Ich bin nicht sicher, wie man das beheben kann. (jemand?)