Programozzunk C#-ban – 7. rész

A sorozat korábbi részeiben igen sok érdekességről volt szó. Ebben a részben a C# objektum modelljének specialitásaival foglalkozunk, mint a kiegészítő metódusok, a statikus osztályok, illetve a zárt és részleges osztályok

Zárt, sealed osztályok

A zárt, angolul sealed osztály egy olyan osztály, amelyből nem lehet örököltetni. Ha egy osztályt a sealed kulcsszóval látunk el, akkor az az osztály nem lehet más osztályok őse. Ez különösen akkor hasznos, ha szabvány implementációkat készítünk, mert ugye a szabvány attól szabvány, hogy le van írva a működés és attól eltérni nem igen ajánlott.

Részleges osztályok

A részleges, angol szóval partial osztályok a .NET 2.0-ban jelentek meg. A részleges osztály egy olyan osztály, amely több forrásfájlban is szerepelhet. Ezt kifejezetten a Windows Forms tervezőhöz találták ki, mivel a Visual Studio a felület megjelenését generálja egy designer.cs fájlba. Így a felhasználó által írt kód és a generált kód elválasztódik egymástól, logikailag azonban mégis összetartoznak. Egy osztály attól lesz részleges, hogy a tulajdonságaiban szerepel a partial szó.

Statikus osztályok

A statikus osztályok olyan osztályok, amelyek csak statikus függvényeket tartalmaznak. Ebből adódóan ezen osztályok nem példányosíthatóak és örököltetni sem lehet belőlük. A statikus osztályok rendelkezhetnek konstruktorral, de nem kötelező. A statikus osztálynak csak egy konstruktora lehet és az paramétereket nem vehet át, mivel nincs is honnan kapnia. A konstruktor ebben az esetben az első függvényhívás előtt fog lefutni.

Az alábbi példa a statikus osztály és konstruktor használatát mutatja be:

using System;
 
namespace _15_statikusosztaly
{
 
    //statikus, mivel static kulcszóval jelöltük meg
    public static class StatikusPelda
    {
        public static int StatikusSzam
        {
            get;
            private set; //privát írható
        }
 
        //statikus osztály konstruktora is statikus
        //elérés módosító itt nem használható
        static StatikusPelda()
        {
            //érték beállítása
            StatikusSzam = 42;
        }
 
        //egy egyszerű statikus függvény
        public static void Test()
        {
            Console.WriteLine("Ez egy statikus metódus");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("A statikus szám értéke: {0}", StatikusPelda.StatikusSzam);
            StatikusPelda.Test();
            Console.ReadKey();
        }
    }
}

Bővítő metódusok

A bővítő metódusok a .NET 3.0 óta léteznek és direkt a LINQ implementálhatósága miatt hozták létre őket. Anno a LINQ készítésénél azzal a problémával találták magukat szembe a programozók, hogy számos alap osztályt bővíteni kellene ahhoz, hogy megvalósítható legyen az elképzelt funkcionalitás.

Ennek azonban vannak hátulütői. Elsősorban az, hogy az alap osztályokhoz kompatibilitási okok miatt nem lehetett hozzányúlni, mivel a .NET 3 a 2.0-ban implementált virtuális gépet használta, illetve visszafelé kompatibilisnek kellett, hogy legyen a 2.0-val.

Így születtek meg a bővítő metódusok, amik olyan metódusok, amelyek lehetőséget biztosítanak arra, hogy egy osztályt bővítsünk újabb függvényekkel  úgy, hogy az eredeti osztályt nem módosítjuk. Módosítás alatt itt az eredeti osztály átírása és örököltetése, majd bővítése értendő. Egyes esetekben például nem is tudjuk örököltetni az osztályt, hogy származtatott típust hozzunk létre.

A bővítő metódusok csak statikus osztályokban helyezhetők el. Ebből adódóan statikus metódusok lesznek. A bővítő metódus attól lesz bővítő metódus, hogy az első paramétere egy this jelzővel ellátott objektum lesz. Ez jelzi a fordító számára, hogy a metódus az első paraméterben megjelölt objektumot bővíti. Ezen kívül számos paramétert átvehet még a bővítő metódus.

Példaképpen nézzünk meg egy olyan bővítő metódust, amely a string típust bővíti egy Caesar titkosító metódussal. A metódusban alkalmazott algoritmus nem a legjobb, lehetne jobbá tenni, de a célnak megfelel.

using System;
using System.Text;
namespace _16_bovitometodus
{
    public static class Bovit
    {
        public static string Caesar(this string Bemenet)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var karakter in Bemenet)
            {
                //UTF-16 miatt minden karakter short szám
                short ertek = (short)karakter;
                //ha a karakter értéke 33 alatti, akkor nem nyomtatható
                //ezért kihagyjuk a titkosítási folyamatból, mert csak bezavarna
                if (ertek < 33) sb.Append(karakter);
                else
                {
                    ertek += 3; //3 pozícióval eltolunk
                    if (ertek > short.MaxValue)
                    {
                        //ha az érték túlmutatna a kódtáblán
                        //akkor kivonjuk a maximális értéket
                        ertek -= short.MaxValue;
                        //majd elcsúsztatjuk 32 pozícióval, hogy nyomtatható
                        //karaktert kapjunk
                        ertek += 32;
                    }
                    //karakterré konvertálunk és hozzá fűzünk
                    sb.Append((char)ertek);
                }
            }
            return sb.ToString();
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            string eredeti = "Ez egy példa szöveg, amit caesar titkosítunk mindjárt";
            Console.WriteLine("Az eredeti szöveg:");
            Console.WriteLine(eredeti);
            Console.WriteLine("-----------------------------------");
            Console.WriteLine("A titkosított szöveg:");
            //bővítő metódus hívása az eredeti string objektumon keresztül
            Console.WriteLine(eredeti.Caesar());
            Console.ReadKey();
        }
    }
}

A bővítő metódusokat akkor érdemes használni, ha alap típusokat szeretnénk bővíteni hasznos függvényekkel, illetve akkor ha a saját osztályainkhoz szeretnénk opcionálisan használható kiegészítéseket írni. Ezen megközelítés előnye, hogy a használat nem kötelező, az alap osztály implementáció pehelysúlyú lehet, amit opcionálisan nehéz bombázóvá lehet előléptetni.

Ügyelni kell azonban az összhangra. Attól, hogy valamit lehet, még nem biztos, hogy kell is. Tehát a bővítő metódusok és saját osztályok kérdésénél érdemes jól átgondolni, hogy mikor legyen valami bővítő metódus és mikor legyen része az alap implementációnak.