Metody rozszerzające

Degusto

Definicja

Czasami pracując z gotowymi klasami brakuje nam jakiś metod np. sprawdzania czy dana liczba jest parzysta lub czy napis jest palindromem. Z pomocą przychodzą nam metody rozszerzające.

Metody rozszerzające to specjalne metody statyczne, które pozwalają nam dodać do istniejących już typów nasze własne metody, przy czym wywoływanie tych metod wygląda jakbyśmy wywoływali normalną metodę dla danego obiektu.
Należy jednak pamiętać, że metody rozszerzającego nie pozwalają nam korzystać z np. prywatnych pól klasy. Jest to tylko tzw. cukier składniowy.

Użycie

Używając metod rozszerzających należy pamiętać, aby klasa, w której znajduje się metoda była statyczna i nie generyczna. W dodatku, żeby użyć metody rozszerzającej powinniśmy znajdować się w tej samej przestrzeni nazw albo dodać przestrzeń nazw poprzez using. W definicji funkcji jako pierwszy argument musi znajdować się typ, do którego będzie dodana metoda rozszerzająca poprzedzony słówkiem this. Metoda rozszerzająca musi być metodą statyczną. Warto wspomnieć, że przy wywoływaniu metody rozszerzającej nie podajemy pierwszego argumentu - jest on automatycznie przekazywany.

Poniżej można zobaczyć prosty przykład:

using System;
 
namespace Program
{
 
    class Program
    {
        static void Main()
        {
            string str = "NAPIS";
 
            str.Wypisz(); // Wywołanie metody rozszerzającej, jakby od zawsze należała do typu string, jak widzimy nie przesyłamy żadnego argumentu
                          // mimo, że w definicji funkcji był argument ze słówkiem this to jednak jest on przesyłany automatycznie
            
            string str2 = str.Polacz("napis"); // Tutaj wywołanie metody rozszerzającej z przekazaniem dodatkowego argumentu
            
            str2.Wypisz();
 
            Console.ReadKey();
        }
    }
 
    static class Rozszerzenia
    {       
        public static void Wypisz(this string str) // Tutaj mamy przykład metody rozszerzającej, która nie pobiera żadnych dodatkowych argumentów
        {
            Console.WriteLine(str);
        }
        
        public static string Polacz(this string pierwszy, string drugi) // Tutaj mamy przykład metody rozszerzającej z dodatkowym argumentem
        {
        	return pierwszy + drugi;
        }
    }
}

Przestrzenie nazw, a metody rozszerzające

Używając metod rozszerzających musimy znajdować się w tej samej przestrzeni nazw lub dodać przestrzeń nazw do użytku poprzez using.

Poniżej powyższy przykład lekko zmodyfikowany:

using System;

namespace Program
{
    using MojeRozszerzenia; // Używanie przestrzeni nazw, w której znajdują się nasze metody rozszerzające

    class Program
    {
        static void Main()
        {
            string str = "NAPIS";

            str.Wypisz(); // Wywołanie metody rozszerzającej, jakby od zawsze należała do typu string, jak widzimy nie przesyłamy żadnego argumentu
                // mimo, że w definicji funkcji był argument ze słówkiem this to jednak jest on przesyłany automatycznie

            string str2 = str.Polacz("napis"); // Tutaj wywołanie metody rozszerzającej z przekazaniem dodatkowego argumentu

            str2.Wypisz();

            Console.ReadKey();
        }
    }
}

namespace MojeRozszerzenia
{
    static class Rozszerzenia
    {
        public static void Wypisz(this string str) // Tutaj mamy przykład metody rozszerzającej, która nie pobiera żadnych dodatkowych argumentów
        {
            Console.WriteLine(str);
        }

        public static string Polacz(this string pierwszy, string drugi) // Tutaj mamy przykład metody rozszerzającej z dodatkowym argumentem
        {
            return pierwszy + drugi;
        }
    }
}

Dodanie metody do typu stworzonego przez kogoś innego

Weźmy sobie prosty przykład. Kolega napisał nam klasę kwadrat, lecz zapomniał napisać metodę, która policzyłaby nam obwód kwadratu. Przy okazji prosił, żebyśmy w żaden sposób nie ruszali jego klasy(możemy z niej tylko korzystać).

Oto przykład jak prosto możemy dodać metodę bez ingerencji w kod kolegi:

using System;

namespace Program
{
    class Program
    {
        static void Main()
        {
            Kwadrat kwadrat = new Kwadrat(5);

            Console.WriteLine(kwadrat.Pole());

            Console.WriteLine(kwadrat.Obwod());

            Console.ReadKey();
        }
    }

    class Kwadrat
    {
        public double Bok { get; set; }

        public Kwadrat(double bok)
        {
            Bok = bok;
        }

        public double Pole()
        {
            return Bok * Bok;
        }

    }

    static class MetodyKwadratu
    {
        public static double Obwod(this Kwadrat kwadrat)
        {
            return 4 * kwadrat.Bok;
        }
    }
}

Ciekawostka

Z racji, że metody rozszerzające to tylko opakowania dla metod statycznych to możemy wywołać metodę rozszerzającą jak zwykłą metodę statyczną.
Poniższe dwie linijki kodu mają takie same działanie, jednak sposób wywołania numer 1 jest o wiele czytelniejszy.

kwadrat.Obwod();
MetodyKwadratu.Obwod(kwadrat);

Podsumowanie

Używając metod rozszerzających możemy w łatwy sposób dodać do istniejącego typu nowe metody bez ingerencji w kod źródłowy - dzięki czemu możemy w łatwy sposób dodać różnego rodzaju opcjonalne rozszerzenia funkcjonalności, zamiast statycznej klasy ze statycznymi metodami. W dodatku podnosimy w ten sposób przejrzystość i jakość kodu.

0 komentarzy