Artykuł

freeimages.com freeimages.com
sty 02 2015
0

Biblioteki warte poznania w C# - Fody

Programowanie nigdy nie było łatwe i szybkie, ale największe wyzwania stoją przed tymi, którzy chcą stworzyć prosty, czytelny, elastyczny i wydajny kod. Czy da się zawsze ładnie połączyć wszystkie elementy tej układanki? Niestety nie, ale to nie oznacza, że powinniśmy łatwo się poddawać.

W moim odczuciu kluczem do sukcesu, powinna być ciągła refaktoryzacja oraz re-używanie wcześniej napisanego kodu. W praktyce okaże się, że każdy projekt można poprawić. Zawsze znajdzie się coś, co można by zrobić lepiej. Dlaczego o tym wszystkim piszę? Powód jest prosty. Chciałbym Wam zaprezentować interesującą bibliotekę, która z pewnością pozwoli Wam na pewną optymalizację napisanego wcześniej kodu. Poznajcie Fody - bibliotekę która modyfikuję IL w czasie procesu budowania aplikacji.

Charakterystyka i zastosowanie

Tytułowa biblioteka Fody, jest bardzo ciekawym rozwiązaniem, które modyfikuje kod IL w trakcie budowy aplikacji, aczkolwiek to stwierdzenie wymaga pewnego doprecyzowania. Sam Fody dostarcza bowiem takiej możliwości, ale konkretne działania wykonywane są dopiero w sytuacji gdy zostanie zainstalowany jakikolwiek z pluginów dostępny dla tej biblioteki i będzie on mógł być faktycznie wywołany w określonym projekcie.

Aby plugin mógł funkcjonować, musi on być dodany do pliku konfiguracyjnego biblioteki. Odpowiednie wpisy są dodawane automatycznie, w sytuacji gdy wtyczki instalujemy za pomocą NuGeta. Poniżej przykładowy plik konfiguracyjny FodyWeavers.xml:

<?xml version="1.0" encoding="utf-8"?>
<Weavers>
  <PropertyChanged/>
  <Usable/>
</Weavers>

To kiedy określony plugin zadziała, zależy często także od jego rodzaju. Np. plugin PropertyChanged oprócz wpisu w pliku konfiguracyjnym. wymaga jeszcze tego by każda klasa w której ma zostać użyty, została oznaczona atrybutem ImplementPropertyChanged. Inaczej zachowuje się plugin Usable, który aktywuje się za każdym razem, gdy mamy do czynienia z kodem wykorzystującym interfejs IDisposable (więcej na ten temat w dalszej części tekstu).

Fody jest więc punktem wejściowym dla sporej liczby pluginów, które w skuteczny sposób uproszczą tworzony przez nas kod.

Warto również wspomnieć, że Fody wpływa tylko na sam proces budowania - samo rozszerzenie nie trafia do katalogu bin po kompilacji;-)

Kiedy warto zastosować bibliotekę Fody?

Fody jest na tyle lekkim rozwiązaniem, że warto z niego skorzystać zawsze, gdy tylko jest w stanie rozwiązać jakiś z naszych problemów. Warto zapoznać się z listą pluginów, umieszczonych tutaj w sekcji Addins list.

Poniżej przykład użycia dwóch popularnych pluginów. Ponieważ sample umieszczone w dokumentacji są proste i czytelne, dlatego też pozwolę je sobie wykorzystać również tutaj.

Fody - PropertyChanged

W połowie 2012 roku popełniłem na łamach tego blogu wpis C# - interfejsy które warto znać. W ramach tego tekstu opisałem kilka popularnych interfejsów, z których warto korzystać na co dzień w C#. Jednym z nich był INotifyPropertyChanged. W tekście opisałem jego przykładową implementację. Jeśli programowaliście cokolwiek w Silverlight/WPF/Windows Phone/Universal Apps, to z pewnością wiecie o co chodzi;-)

W każdym bądź razie w tekście przedstawiłem standardową, odrobinę problematyczną implementację. W międzyczasie pojawiło się nowe rozwiązanie, wykorzystujące nowe możliwości języka, które pojawiły się przy okazji premiery C# w wersji 5.0. Przykład nowej konstrukcji można znaleźć tutaj. Nowe podejście jest już dużo lepsze, ale wciąż wymaga ingerencji w kod każdego propertisa. Z Fody.PropertyChanged możemy cały ten proces zautomatyzować. Spójrzcie na przykładowy kod:

[ImplementPropertyChanged]
public class Person 
{        
    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }
}

Na pozór ta klasa wygląda niewinnie i bardzo pospolicie, aczkolwiek pewną niewiadomą jest atrybut stojący przy deklaracji klasy. Jeśli uważnie czytaliście wcześniejsze akapity, to z pewnością pamiętacie że w praktyce jest to aktywator naszego pluginu. Skompilowana zostanie odrobinę inna konstrukcja:

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set 
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Jak widać, w wyniku zastosowania pluginu oraz naszego magicznego atrybutu, uzyskaliśmy kod, który w pełni implementuje interfejs INotifyPropertyChanged. Na dodatek nasze bazowe propertisy, wykorzystują teraz zmienne lokalne, które zostały dodane przez wtyczkę. Trudno nie dostrzec tutaj benefitów tego rozwiązania, zwłaszcza gdy w naszym projekcie mamy więcej tego typu klas;-)

Fody - Usable

Druga wtyczka również w pewnym sensie odnosi się do interfejsu, który już wcześniej opisywałem. W tym przypadku chodzi o IDisposable. Interfejs ten powinny implementować wszystkie klasy, które z założenia mają pewne zasoby do uwolnienia po zakończeniu swojej pracy. W większości ten problem dotyczy np. różnych implementacji klasy Stream.

Wtyczka Usable wykrywa kod, który korzysta z tego interfejsu i automatycznie przerabia go w taki sposób, by wykorzystywał on blok using. Spójrzmy na przykładowy kod bazowy:

public void Method()
{
    var w = File.CreateText("log.txt");
    w.WriteLine("Hello World.");
}

Po zastosowaniu Usable dostaniemy coś takiego:

public void Method()
{
    using (var w = File.CreateText("log.txt"))
    {
        w.WriteLine("Hello World.");
    }
}

Dzięki temu plik zostanie automatycznie zapisany i zwolniony przez program, zaraz po wyjściu z bloku Using;-)

Podsumowanie

Fody to biblioteka o sporych możliwościach, która może przynieść sporo korzyści, ale również i szkód, w sytuacji gdy zostanie ona nieprawidłowa użyta. Zawsze pamiętajcie by w kodzie (np. w komentarzu) znalazła się informacja, że w określonym miejscu został użyty Fody. O ile w przypadku pierwszego pluginu było to oczywiste (wykorzystaliśmy tam dedykowany rozwiązaniu atrybut), o ile w drugim przypadku nie było to do końca jasne i mogło to skutecznie utrudnić pracę innemu programiście.

Nie mniej jednak Fody jest rozwiązaniem zdecydowanie godnym polecenia, ponieważ w wielu przypadkach może ukrócić i uprościć tworzony przez nas kod. Polecam zapoznać się z bogatą listą dostępnych rozszerzeń;-)

Metryka

Podoba Ci się ten wpis? Powiedz o tym innym!

Send to Kindle

Komentarze

blog comments powered by Disqus