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()); }