FormatWith 2.0

Niejednokrotnie sklejałem ze sobą wiele stringów na przykład w ten sposób:

string ala = "Ala";
string ma = "ma";
int dwa = 2;
string koty = "koty";
string zdanie = ala + " " + ma + " " + dwa.ToString() + " " + koty + ".";

Problem w tym, że ta metoda jest mało estetyczna oraz słabo wydajna, ponieważ w ten sposób tworzonych jest wiele pomocniczych obiektów typu string, co powoduje spadek wydajności. Tutaj z pomocą przychodzi nam metoda string.Format(), która wypełnia zadany string tekstem wartości przesłanych obiektów, np:

string ala = "Ala";
string ma = "ma";
int dwa = 2;
string koty = "koty";
string zdanie = string.Format("{0} {1} {2} {3}.", ala, ma, dwa, koty);

Wyobraźmy sobie sytuację, że nasz sklejany string jest znacznie dłuższy oraz posiada większą ilość przesyłąnych obiektów. Na dodatek nie tworzy tak oczywistej stuktury jak podałem w przykładzie powyżej. W takim wypadku ciężko jest stwierdzić co kryje się za {0} czy też {1}. Można to odczytać z kontekstu lub z kolejności przesyłanych obiektów, jednakże staje się to na dłuższą metę irytujące. Problem ten rozwiązał James Newton-King, który opisuje na swoim blogu stworzoną metodę rozszerzającą FormatWith 2.0. Jest ona świetnym rozwiązaniem co prezentują poniższe przykłądy zastosowań.

DateTime teraz = DateTime.Now;
"Dziś jest {DayOfWeek} - {DayOfYear} dzień w roku.".FormatWith(teraz);
MembershipUser user = Membership.GetUser();
lStatus.Text = "{UserName} zalogował się {LastLoginDate}".FormatWith(user);
"Nazywam się {name}, a liczba PI = {PI}".FormatWith(new { name = "Łukasz", Math.PI });
var osoba = new
{
    nick = "Acid",
    data = new DateTime(1986, 6, 1),
    tel = new[]
    {
        new { kom = "+48600100200" },
        new { kom = "+48888123456" }
    }
};
Console.WriteLine("{nick} z datą {data} o numerze tel {tel[0].kom}".FormatWith(osoba));

Cały mechanizm działania metody opiera się na wyrażeniach regularnych oraz klasie DataBinder. W przypadku zastosowania jej w aplikacjach desktopowych należy dodać w projekcie referencję do System.Web.

Na sam koniec oczywiście najważniejsze – kod źródłowy rozszerzenia:

public static string FormatWith(this string format, object source)
{
    if (format == null)
        throw new ArgumentNullException("format");

    Regex r = new Regex(@"(?<start>\{)+(?<property>[\w\.\[\]]+)(?<format>:[^}]+)?(?<end>\})+",
      RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);

    List<object> values = new List<object>();
    string rewrittenFormat = r.Replace(format, delegate(Match m)
    {
        Group startGroup = m.Groups["start"];
        Group propertyGroup = m.Groups["property"];
        Group formatGroup = m.Groups["format"];
        Group endGroup = m.Groups["end"];

        values.Add((propertyGroup.Value == "0")
          ? source
          : DataBinder.Eval(source, propertyGroup.Value));

        return new string('{', startGroup.Captures.Count) + (values.Count - 1) + formatGroup.Value
          + new string('}', endGroup.Captures.Count);
    });

    return string.Format(null, rewrittenFormat, values.ToArray());
}

Promuj

Leave a Reply

Your email address will not be published. Required fields are marked *