fbpx

Metody to bez wątpienia jedna z podstaw każdego języka programowania. Wydawać by się mogło, że nie mogą nas niczym zaskoczyć, bo przecież są prostą konstrukcją. Metoda składa się zazwyczaj z modyfikatora dostępu, typu zwracanego, nazwy, parametrów oraz ciała funkcji. Tym razem zbadam specjalny typ metody, który występuje między innymi w języku C#, czyli metody lokalne.

Z tego artykułu dowiesz się między innymi:

  • Czym są metody lokalne?
  • W jaki sposób implementowane są metody lokalne w języku C#?
  • Jak wygląda dostęp do zmiennych lokalnych w metodach lokalnych?

Zanim zaczniemy, na dole jest sekcja komentarzy, jeśli wpis Ci się spodobał, to został po sobie komentarz. Zaczynamy!

Zatrzymaj się!


Książki to obowiązkowa pozycja dla każdego zainteresowanego programowaniem!

Jest to zdecydowanie jedno z najlepszych źródeł do nauki programowania! Zyskasz przewagę w branży IT i osiągniesz dużo jako deweloper.


Czym są metody lokalne?

Myśląc o metodach lokalnych, od razu przychodzi nam do głowy pomysł umieszczenia metody w metodzie. I jest to dobre myślenie. W dużym skrócie tak właśnie to wygląda. Możliwość ta została wprowadzona w 7 wersji języka C#, by poprawić czytelność kodu. 

Sama metoda lokalna jednak nie odnosi się tylko do innych metod. Może występować również we właściwościach, konstruktorach, finalizatorach, akcesorach zdarzeń czy nawet w funkcjach anonimowych. Konstrukcja może wydawać się dziwna, ale czytelność kodu, jaką możemy dzięki metodom lokalnym zyskać, bywa ogromna. 

Oczywiście nie napisałbym artykułu o metodach lokalnych, gdyby nie było żadnych znaczących różnic w stosunku do zwykłych metod stosowanych w klasach. Zobaczmy jednak na początku, co łączy metody lokalne ze zwykłymi metodami:

  • Zwraca wartość lub jest typu void;
  • Może mieć modyfikator unsafe oraz async;
  • Posiada parametry, w tym także opcjonalne;
  • Może być generyczna;

Jak widać, łączy je sporo. Różni je natomiast:

  • Metody lokalne nie mogą mieć modyfikatorów dostępu poza private oraz modyfikatorów external,  virtual, new, override, static czy abstract;
  • Brak możliwości dodania atrybutów;
  • Nie mogą mieć tych samych nazw, co inna metoda lokalna w tej samej nadrzędnej jednostce. Brak możliwości przeciążenia;

Różnice jak widać, są i to wcale nie takie subtelne. 

W jaki sposób implementowane są metody lokalne w języku C#?

Implementacja jest banalnie prosta. Od strony środowiska CLR nie ma znaczenia dla kompilatora, czy ma do czynienia z lokalną metodą, czy ze zwykłą. Lokalna zostaje przekształcana do zwykłej.

Poniżej przykład produkcyjny, który jest wzorcowym przykładem podawanym przez Microsoft.

private static string GetText(string path, string filename)
{
     var reader = File.OpenText($"{AppendPathSeparator(path)}{filename}");
     var text = reader.ReadToEnd();
     return text;

     string AppendPathSeparator(string filepath)
     {
        return filepath.EndsWith(@"\") ? filepath : filepath + @"\";
     }
}

W pierwszej linii deklaruję metodę zwracającą tekst z odczytanego pliku. Zobacz, jak sprytnie jest zbudowany obiekt reader, gdzie w metodzie OpenText używamy metody lokalnej AppendPathSeparator. Jej zadanie jest proste. Jeśli na końcu nie ma znaku '\’, to jest on doklejany do przekazanej ścieżki.

Dalej metoda nadrzędna wykonuje swoje działanie aż do instrukcji return. Zauważ, że funkcja lokalna jest zadeklarowana po return i nie powoduje to problemów z jej wywołaniem przed zwróceniem wartości z funkcji nadrzędnej.

Jak wygląda dostęp do zmiennych lokalnych w metodach lokalnych?

Możesz się domyślać, że podczas wprowadzenia metod lokalnych do języka C# zmienia się nieco dostęp do zmiennych. Zasięgi zmiennych zostają nieco zaburzone i zaczynają obowiązywać dodatkowe reguły.

Zacznę jednak od podstaw. Przede wszystkim deklaracja metody lokalnej musi wystąpić po zadeklarowaniu wszystkich zmiennych. Tak jak w standardowym kodzie, tak samo w tym przypadku nie możemy używać zmiennych zadeklarowanych już za metodą. Zobacz przykłady niżej.

void Print1()
{
    for(int k = 0; k < 5; k++)
    {
        PrintMess(); // Błędne wywołanie
    }
    
    void PrintMess()
    { 
        Console.WriteLine(k); // Zmienna k nie jest w zasięgu funkcji lokalnej
    }
}
void Print2()
{
    for(int k = 0; k < 5; k++)
    {
        PrintMess(); // Jestok

        void PrintMess()
        { 
            Console.WriteLine(k); // Zmienna k jest w zasięgu funkcji lokalnej
        }
    }
}

Dodatkowo trzeba uważać na przechwytywanie parametrów ref z metod nadrzędnych. Nie można w metodzie lokalnej przechwycić takiego parametru użytego w metodzie wyżej. Zresztą podobnie ma się sytuacja z funkcjami anonimowymi. Zobacz kod poniżej.

void Print3(ref string text)
{
        // Jakaś część kodu używająca zmiennej ref text

        PrintMess(); // Błędne wywołanie
        void PrintMess()
        { 
            Console.WriteLine(text); // Błąd. Zmienna ref nie może być używana
        }
}

Kolejne rzeczy, na które musimy uważać, to wykorzystywanie zmiennych, które nie mają przypisanej wartości i wiadomo, że nie możemy w metodach lokalnych przypisywać wartości do pól tylko do odczytu. Zobacz kod poniżej.

void Print4()
{
        string z;

        PrintMess(); // Błędne wywołanie
        void PrintMess()
        { 
            Console.WriteLine(z); // Błąd. Zmienna z nie może być używana, ponieważ nie ma przypisanej wartości
        }
}
class Print()
{
      private readonly int z;
      
      public SetValue()
      {
           SetROVal(); // Błędne wywołanie
           
           void SetROVal()
           { 
               z = 42 // Błąd. Nie można przypisać vartości
           }
    }
}

To tyle jeśli chodzi pracę w metodach lokalnych ze zmiennymi. Niby drobne niuanse, ale trzeba uważać i o nich pamiętać. 

Funkcje lokalne – podsumowanie

Jak widzisz, funkcje lokalne są proste i pomagają poprawiać czytelność. Zamiast tworzyć metodę prywatną, której użyjemy raz jako metodę normalną, to lepiej w metodzie nadrzędnej zrobić z niej metodę lokalną. 

Ciekawe jest to, że funkcje lokalne wprowadzono do języka C# z takim opóźnieniem. Nie do końca rozumiem, dlaczego tak z tym zwlekano. Dla kompilatora i tak nie ma różnicy.

Newsletter

Nie przegap i dołącz już dziś do 838 osób będących w tym Newsletter! Otrzymuj co niedzielę o godzinie 20 listę kilku ciekawych tematów, które miałem okazję obserwować w mijającym tygodniu.

Tematy będą głównie techniczne, ale czasami pojawi się coś, co może wprowadzi Cię w stan zadumy i zmusi do dyskusji w szerszym gronie. Zero spamu!

Autor

Programista .NET i Python. Autor książki "Programistą być".

Napisz komentarz

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.

SPRAWDŹ POLECANĄ KSIĄŻKĘ. Najlepsze materiały do nauki programowania!

X