lokal-funksiyalar

Lokal funksiyalar

C# 7.0 versiyasında gələn yeniliklərdən biri lokal funksiyaların(local function) yaradılmasıdır. Bu məqalədə lokal funksiyaları private metodlar və lambda ifadələr ilə müqayisə edəcək, lokal funksiyaların üstünlüklərini göstərməyə çalışacam.

               C#-da klas dizayn edən zaman bir çox hallarda public metodları daha kiçik hissələrə parçalamaq lazım olur. Metodların düzgün dizayn olunması , məsuliyyət bölgüsününün düzgün yerinə yetirilməsi və clean code yaza bilmək üçün bəzi public metodların içərisindəki bir sıra kod parçasını ayrıca private metoda çıxardırıq. Amma ki bu heç də həmişə özünü doğruldan variant deyil.

               Çünki əgər həmin private metod klas daxilində başqa metod tərəfindən istifadə olunmayacaqsa sadəcə bir metod üçün private metod yaradılması tam da doğru sayılmır. Bu tip problemləri aradan qaldırmaq üçün C# dilinə local funksiyalar əlavə olunub.

Sual 1. Lokal funksiyalar ilə private metodların fərqi nədir?

               Əgər klas dizayn edən zaman əgər yaranan private metod yalnız bir metodun işini təmin etməyə xidmət edirsə ozaman lokal metod istifadə etmək lazımdır. Yox əgər, private metod üçün ayırdığımız kod bloku birdən artıq metoda xidmət edirsə ozaman private metod doğrudur.

               Lokal metodlar digər metodların tərkibində elan olunur və onların görünmə sahəsi həmin metodla məhdudlaşır.

               Lokal metodlar heç bir əlçatma modifikatoru ( private,public və.s) ilə göstərilə bilməz. Yalnız async və unsafe sözləri öndə gələ bilər və ya bunlarsız istifadə oluna bilər. Metodun daxilindəki dəyişən lokal funksiya üçün də görünən olur.

Sadə bir lokal funksiyaya baxaq:

class Program
   {
       static void Main(string[] args)
       {
           int x = DoOperation();
           //Calc metodunu bu konteksdə çağırmaq olmaz, çünki DoOperation() kontekstindədir.
       }
 
       private static int DoOperation()
       {
           //bu dəyişən lokal funksiya üçün qlobal sayılır..
           int sharedValue = 34;
 
           int x = Calc(14, 21, 34, 67);
 
           return x;
 
           //bu metod lokal funksiyadır, metodun daxilində elan olunub!
           int Calc(int numberOne, int numberTwo, int numberThree,int numberFour)
           {
               return numberOne * numberThree + numberThree +numberFour + sharedValue;
           }
       }
   }

Lokal funksiyalar kompilyasiya vaxtı private metodlara çevrilirlər.

Lokal funksiyalara həmçinin atributlar tətbiq etmək olmur! Lokal funksiyalara ona görə əlçatma modifikatoru yazılmır ki, onsuz da kompilyasiya zamanı private metodlara çevrilirlər.

Sual 2. Lokal funksiyaların lambda ifadələrdən fərqli və üstün tərəfləri nələrdir?

               Əgər internetdə axtarış etsəniz lokal funksiyaların ən çox lambda ifadələrlə müqayisə olunduğunu görərsiniz. Həqiqətən də bəzən onların hansı birinin seçilməsi sadəcə proqramçının zövqünə və yazma stilinə qalır. Amma ki aralarında ciddi fərqlər də az deyil. Məqalənin bu bölməsində bu iki məfhumu fərqləndirməyə çalışaq.

1)     Lokal funksiyalar adlandırılmış metodlardır amma lambda ifadələr anonim metodlardır hansı ki, Func və ya Action deleqatı istifadə edirlər.

2)     Lokal funksiyalar elan olunduğu metod daxilində “qlobal” olur, yəni elan olunduğu metodun həm evvəlində həm də sonunda elan oluna və çağrıla bilir amma lambda ifadələr yalnızda elan olunduğu sətirdən sonra çağrıla bilir.

Əgər elan olunduğu sətirdən əvvəl çağırsanız kompilyator sizə bu kodu lokal funksiyaya çevirməyi təklif edəcək.

3)Metodun arqumenti və geri qaytardığı nəticə lokal funksiyanın tərkib hissəsidir amma lambda ifadələrdə həmin elementlər lambda ifadənin dəyişən tipinin tərkib hissəsi sayılır!

4)2-ci bəndi nəzərə alaraq rekursiv metodların yaradılması üçün ən yaxşı mexanizm məhz lokal funksiyalardır!!!

 


5)Lambda ifadələr elan olunan kimi kompilyasiya vaxtı deleqatlara çevrilir, lokal funksiayalar isə private metoda çevrilirlər.

6)Lambda ifadələr istifadə edən zaman kompilyator statik analiz apara bilmir, amma funksiyalar hesabına bu mümkündür.

İndi isə koda lokal funksiya ilə baxaq:

7)Lambda ifadələrdə yield return-ə icazə verilmir amma lokal funksiyalarda icazə verilir. Bu isə lokal funksiyaların mənə görə ən böyük özəlliklərindən biridir ki , özü ilə növbəti fərqi gətirir.

8) yield return ilə exception qaldırma prosesini tam dəqiq emal etmək olur. Beləki, əgər lokal metod işə salmasaq, bildiyimiz kimi, yield return tipli metodlar yalnız sadalama işə salınan zaman məlumatı sadalamağa başlayırlar.(sonradan icra olunma prosesi baş verir). Bu isə kodda problem varsa sonradan müəyyən olunmasına səbəb olur. Real nümunədə bunu izah edək.

Təsəvvur edəkki ,aşağıdakı kod nümunəsi verilib.

   class Program
    {
        static void Main()
        {
            try
            {
                IEnumerable<int> datas = GetAppValues(345, 346, 234, 346, 23, 45, 67, 89, 345, 324, 345, 423);
                Console.WriteLine("Starting enumeration...");


                foreach (int data in datas)
                {
                    Console.Write($" {data} ");
                }
            }
            catch(Exception exp)
            {
                Console.WriteLine(exp.Message);
                Console.WriteLine(exp.StackTrace);
            }
        }


        public static IEnumerable<int> GetAppValues(params int[] arrayData)
        {
            if (arrayData.Length == 0)
                throw new ArgumentOutOfRangeException("array can't be empty");
            if (arrayData.Length >10)
                throw new ArgumentOutOfRangeException("array length must be max 10 number");

                int[] appNumbers = { 45, 67, 89 };

                for (int i = 0; i < arrayData.Length; i++)
                {
                    for (int a = 0; a < appNumbers.Length; a++)
                    {
                        if (arrayData[i] == appNumbers[a])
                            yield return arrayData[i];
                    }

                } 
        }
    }

Kodu icra edən zaman belə bir exception və yazı görürük:

İndi isə kodu lokal metod ilə yazaq:

 class Program
    {
        static void Main()
        {
            try
            {
                IEnumerable<int> datas = GetAppValues(345, 346, 234, 346, 23, 45, 67, 89, 345, 324, 345, 423);
                Console.WriteLine("Starting enumeration...");


                foreach (int data in datas)
                {
                    Console.Write($" {data} ");
                }
            }
            catch(Exception exp)
            {
                Console.WriteLine(exp.Message);
                Console.WriteLine(exp.StackTrace);
            }
        }


        public static IEnumerable<int> GetAppValues(params int[] arrayData)
        {
            if (arrayData.Length == 0)
                throw new ArgumentOutOfRangeException("array can't be empty");
            if (arrayData.Length >10)
                throw new ArgumentOutOfRangeException("array length must be max 10 number");
            

              //lokal metodun çağırılması
            return GetAppSameValues();

             //lokal metodun yaradılması
            IEnumerable<int> GetAppSameValues()
            {
                int[] appNumbers = { 45, 67, 89 };


                for (int i = 0; i < arrayData.Length; i++)
                {
                    for (int a = 0; a < appNumbers.Length; a++)
                    {
                        if (arrayData[i] == appNumbers[a])
                            yield return arrayData[i];
                    }


                }
            }
        }
    }

Verilən kodu icra etsək görərik ki, exception hadisəsindən əvvəl hər hansı bir başqa kod icra olunmur!!!



Tural

Tural Süleymani

Süleymani Tural Microsoft-un MCSD statuslu mütəxəssisidir, 2008-ci ildən bu yana proqramlaşdırma üzrə tədris aparır

Müəllifin bu dildə ən son postları

Bu yazıları da bəyənə bilərsiniz