Programowanie

Linq Aggregate i String Builder…

Jak agregować tekst do String Buildera? Zazwyczaj robi się to tego typu kodem:

W tym przypadku funkcja CollectHtml(…) uzupełnia obiekt String Buildera o kolejne elementy w ten sposób:

Ale przecież można o wiele prościej – czego niedawno nauczył mnie kolega z zespołu 🙂

Oczywiście to tak łatwo nie zadziała, bo teraz CollectHtml(…) powinien zwracać obiekt String Buildera. Dodatkowo polepszy to sytuację w tej funkcji, bo funkcja która zmienia stan obiektu, a nie zwraca rezultatu (czyli wykorzystuje “zakłócenia w otoczeniu” do działania) to zło.

Plusy do obsługi, plusy do działania. Czytelność w tym wypadku jest rzeczywiście kwestią gustu i znajomości Linq…

5 thoughts on “Linq Aggregate i String Builder…

  1. Pingback: dotnetomaniak.pl
  2. public string GetPagedHtml() =>
    Pages.Aggregate(new StringBuilder(), AggregatePage).ToString();

    private static StringBuilder AggregatePage(StringBuilder sb, Page page) => page.CollectHtml(sb);

    internal StringBuilder CollectHtml(StringBuilder sb)
    {
    GeneratePageHeader(sb);
    GeneratePageFromSections(sb);
    GeneratePageFooter(sb);
    return sb;
    }

    1. Wolę group method od lambdy, bo logiki w lambdzie już nie można użyć powtórnie, trzeba ją pisać ponownie, dodatkowo tasiemiec mniejszy.

    2. Po co obiekt agregujący ma mieć świadomość, o szczegółach implementacyjnych typu page.Index==0. Co więcej nawet CollextHtml nie powinien się tym zajmować, skoro GeneratePageHeader siedzi sobie na page i wewnątrz może sprawdzić ten warunek.

    3. Ciało metody CollectHtml też się prosi o bardziej funkcyjne podejście, ale z braku fajnych mechanizmów kompozycji w c# (za wyjątkiem sztukowania przy pomocy extension) będzie to, albo wyglądać brzydko, albo za dużo kodu do napisania.

    Gdyby to był F# i metody GenerateXXX zwracały sb mogło by to wyglądać tak:
    let CollectHtml sb:StringBuilder =
    sb |> GeneratePageHeader |> GeneratePageFromSections |> GeneratePageFooter

  3. 1. Zgadzam się, ale nie zamierzam tego drugi raz wykorzystywać. Jakbym musiał to ok.
    2. Tu chodzi mi raczej o nie ukrywanie tego faktu. U Ciebie w ogóle ta informacja zniknęła. Jest szczegółem implementacyjnym w prywatnej funkcji wykorzystującym zmienną dla niej globalną – IMHO to zło.
    3. Zgadzam się, to co podałeś w F# da się i w C# tylko za pomocą kropek, ale nie wiem czy od tego czytelność rośnie. Czytamy z góry do dołu, a nie w bok.

    1. Z ad.2 kompletnie się nie zgadzam. Wyobraź sobie jaki będzie bajzel jak na wyższym poziomie abstrakcji będziesz robił całą masę ifów do szczegółów implementacyjnych niższego poziomu.

      1. Zgadzam się, że należy to całkowicie inaczej przerobić, Albo nawet przepisać cały program od 0 (bo to co się tam dzieje…), ale co do tego fragmentu, wolałbym to jednak widzieć, że to specjalny case. Pewnie tu się nie zgodzimy, ale tak czasem musi być 🙂

Leave a Reply to paweltymura Cancel reply

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