Személyes eszközök
Keresés

 

A InfoWiki wikiből


Tartalomjegyzék

Téglalap

Készítsünk olyan programot, amely téglalapokat kezel. Egy téglalapot jellemez a 'szélessége', és a 'magassága', valamint a koordinátarendszerben a bal felső sarkának 'x','y' koordinátája. Ez gyakorlatilag egy 4 mezőt tartalmazó rekordot jelent. Számoljuk ki ezen téglalap kerületét. Oldjuk meg a téglalap adatainak kezelését biztonságosan.

Az alapfeladat

Készítsük el a téglalap adatait tartalmazó rekord deklarációját.

// Teglalap alap rekord
class Teglalap
{
 public int szelesseg;
 public int magassag;
 public int x;
 public int y;
}

Készítsünk olyan programot, amely létrehoz egy ilyen téglalapot példányt, és a mezők értékét feltölti billentyűzetről. A program ezek után írja ki a téglalap kerületét.

// Teglalap kezelő főprogram
class Foprogram
{
 //..........................................................................
 public static void Main()
 {
Teglalap t;
t = new Teglalap();
t.x = -20;
t.y = +30;
t.szelesseg = 10;
t.magassag = 20;
Console.WriteLine("A teglalap kerulete = {0}", (t.szelesseg+t.magassag)*2);
 }
 //..........................................................................
}

Alkalmazzunk a kerület kiszámítására függvényt:

// Teglalap kezelő főprogram + kerületszámító függvény
class Foprogram
{
 //..........................................................................
 public static int Kerulet( Teglalap t )
 {
return 2*(t.szelesseg + t.magassag);
 }
 //..........................................................................
 public static void Main()
 {
Teglalap t;
t = new Teglalap();
t.x = -20;
t.y = +30;
t.szelesseg = 10;
t.magassag = 20;
Console.WriteLine("A teglalap kerulete = {0}", Kerulet(t) );
 }
 //..........................................................................
}
  • Vegyük észre, hogy a rekord mezői előtt álló 'public' szó a mező védelmi szintje. Egyúttal megadja, hogy a program mely soraiban, mely területén lehet az adott mezőre hivatkozni. Mivel a főprogramban próbálunk a mezőkre hivatkozni, így ott csak a 'public' védelmi szintű mezőket érhetjük el. Amennyiben bármely mező védelmi szintjét módosítjuk ('protected', 'private'), úgy a főprogram fordításakor hibaüzenetet kapunk. Próbáljuk ki!

A rekord alapú vektor

Készítsünk a téglalapokból egy 30 elemű vektort, és töltsük fel a 30 téglalap rekord mezőit véletlen értékekkel. Határozzuk meg, melyik ezek közül a legnagyobb kerületűt, és irassuk ki a paramétereit.

// Teglalap kezelése vektorban
class Foprogram
{
    //..........................................................................
    public static int Kerulet(Teglalap t)
    {
        return 2 * (t.szelesseg + t.magassag);
    }
    //..........................................................................
    public static void Main()
    {
        Teglalap[] tomb = new Teglalap[30];
        // --- rekordok létrehozása a memóriában ---
        for (int i = 0; i < tomb.Length; i++)
            tomb[i] = new Teglalap();
        // --- rekordok mezőinek feltöltése  ---
        Random rnd = new Random();
        foreach (Teglalap t in tomb)
        {
            t.x = rnd.Next(-100, 100);
            t.y = rnd.Next(-100, 100);
            t.szelesseg = rnd.Next(10, 100);
            t.magassag = rnd.Next(10, 100);
        }
        // --- maximális elem sorszámának kiválasztása ---
        int maxI = 0;
        for (int i = 1; i < tomb.Length; i++)
            if (Kerulet(tomb[i]) > Kerulet(tomb[maxI]))
                maxI = i;
        // --- kiírás ---
        Console.WriteLine("A teglalap adatai: X={0}, Y={1}, Szelesseg={2}, Magassag={3}",
            tomb[maxI].x,
            tomb[maxI].y,
            tomb[maxI].szelesseg,
            tomb[maxI].magassag
        );
    }
    //..........................................................................
}
  • Vegyük észre, hogy maga a vektor deklarációja nem jelenti azt, hogy a 30 darab téglalap rekord be is került a memóriába. A vektor csak a későbbi téglalapok memóriacímét őrzi - ebben az állapotában azonban csak 30 darab 'null' értéket, jelezvén hogy még nem tartalmaz használható memóriacímet:
Teglalap[] tomb = new Teglalap[30];
  • A téglalap rekordokat egyesével kell a memóriában kialakítani, helyüket lefoglalni, és a memóriacímeket bemásolni a vektor megfelelő helyére:
for (int i = 0; i < tomb.Length; i++)
  tomb[i] = new Teglalap();

A rekord alapú lista

Ismételten oldjuk meg a feladatot, de ezúttal ne vektort, hanem listát (ArrayList) használjunk fel. Ha ArrayList-et kívánunk használni egy programban, akkor a 'System.Collections' névteret kell a 'using' segítségével megnyitni!

// Teglalap kezelése ArrayList-ben
class Foprogram
{
    //..........................................................................
    public static int Kerulet(Teglalap t)
    {
        return 2 * (t.szelesseg + t.magassag);
    }
    //..........................................................................
    public static void Main()
    {
        ArrayList lista = new ArrayList();
        // --- rekordok létrehozása a memóriában ---
        for (int i = 0; i < 30; i++)
        {
            Teglalap t = new Teglalap();
            lista.Add( t );
        }
        // --- rekordok mezőinek feltöltése  ---
        Random rnd = new Random();
        foreach (Teglalap t in lista)
        {
            t.x = rnd.Next(-100, 100);
            t.y = rnd.Next(-100, 100);
            t.szelesseg = rnd.Next(10, 100);
            t.magassag = rnd.Next(10, 100);
        }
        // --- maximális elem sorszámának kiválasztása ---
        int maxI = 0;
        for (int i = 1; i < lista.Count; i++)
            if (Kerulet(lista[i] as Teglalap) > Kerulet(lista[maxI] as Teglalap))
                maxI = i;
        // --- kiírás ---
        Console.WriteLine("A teglalap adatai: X={0}, Y={1}, Szelesseg={2}, Magassag={3}",
            (lista[maxI] as Teglalap).x,
            (lista[maxI] as Teglalap).y,
            (lista[maxI] as Teglalap).szelesseg,
            (lista[maxI] as Teglalap).magassag
        );
    }
    //..........................................................................
}
  • Figyeljük meg, hogy 'tomb' helyett most 'lista' nevű változót használunk, amelynek típusa 'ArrayList'. Egy ilyen lista létrehozása után üres. Elemszámát nem a '.Length', hanem a '.Count' property írja le. Mivel induláskor üres a lista, az elemeket hozzá kell adni a listához az '.Add(...)' metódusával:
for (int i = 0; i < 30; i++)
{
    Teglalap t = new Teglalap();
    lista.Add( t );
}
  • Ezt a fenti műveletet természetesen egy lépésben is elvégezhetjük:
for (int i = 0; i < 30; i++)
   lista.Add( new Teglalap() );
  • A fenti ciklusban még nem használhatjuk a '.Count' tulajdonságot, mivel annak értéke (a lista létrehozása után) egyelőre '0'. Ezért a hozzáadandó elemek számát direktben kell megadni ('30').
  • A 'foreach' ciklus nem változott, mivel annak jelen példában mindegy, hogy tömbbel vagy listával dolgozunk. Többek között ezért is érdemes használni.
  • A további kódrészek a miatt módosultak, mivel az 'ArrayList' tetszőleges típusú elemek (Object alaptípus) tárolására képes, és e miatt az elemek kiolvasása után típuskényszerítéseket kell alkalmazni ('lista[i] as Teglalap)'. Az 'as' típuskényszerítés helyett természetesen alkalmazhatjuk a hagyományos módot is: '(Teglalap)lista[i]', de ekkor több zárójelet kell alkalmazni, pl: '((Teglalap)lista[i]).x' módon.

A rekord alapú típusos lista

Ismételten oldjuk meg a feladatot, de ezúttal ne vektort, hanem típusos listát (generic) használjunk fel.

// Teglalap kezelése generic listával
class Foprogram
{
 //..........................................................................
 public static int Kerulet(Teglalap t)
 {
     return 2 * (t.szelesseg + t.magassag);
 }
 //..........................................................................
 public static void Main()
 {
     List<Teglalap> lista = new List<Teglalap>();
     // --- rekordok létrehozása a memóriában ---
     for (int i = 0; i < 30; i++)
         lista.Add( new Teglalap() );
     // --- rekordok mezőinek feltöltése  ---
     Random rnd = new Random();
     foreach (Teglalap t in lista)
     {
         t.x = rnd.Next(-100, 100);
         t.y = rnd.Next(-100, 100);
         t.szelesseg = rnd.Next(10, 100);
         t.magassag = rnd.Next(10, 100);
     }
     // --- maximális elem sorszámának kiválasztása ---
     int maxI = 0;
     for (int i = 1; i < lista.Count; i++)
         if (Kerulet(lista[i]) > Kerulet(lista[maxI]))
             maxI = i;
     // --- kiírás ---
     Console.WriteLine("A teglalap adatai: X={0}, Y={1}, Szelesseg={2}, Magassag={3}",
         lista[maxI].x,
         lista[maxI].y,
         lista[maxI].szelesseg,
         lista[maxI].magassag
     );
 }
 //..........................................................................
}
  • A típusos lista használatához a 'System.Collections.Generic' névteret kell megnyitni. Ez a névtér csak a C# 2.0-ban, a Visual Studio 2005-ben létezik csak, korábbi verzióban nem elérhető.
  • A generic lista egy típusos listát jelent, ahol a listában lévő elemek típusát meg tudjuk adni: 'List<Teglalap>'. Az elemek típusnevét a '<..>' jelek közé kell írni. Ennek két előnye van: egyrészt a fordítóprogram ellenőrzi, hogy ettől eltérő (ezzel nem kompatibilis) típusú elemet ne adhassunk a listához. Másrészt az elemek kiolvasásakor a fordító tudja, hogy az elem típusa milyen, ezért a további típuskényszerítésekre nincs szükség (sem az 'as', sem a hagyományos formájú típuskényszerítésre nincs szükség).

A kerület metódus bevezetése

A kerületszámító függvényt metódus formájában építsük be a téglalap osztályba.

// Teglalap osztály interface
class Teglalap
{
 public int szelesseg;
 public int magassag;
 public int x;
 public int y;
 public int kerulet() {...}
}


// Teglalap osztály kidolgozva
class Teglalap
{
 public int szelesseg;
 public int magassag;
 public int x;
 public int y;
 //..........................................................................
 public int kerulet() 
 {
     return 2 * (szelesseg + magassag);
 }
 //..........................................................................
}
  • A metódust az osztály belsejébe kell írni. A példányszintű metódusok előtt nem szerepel a 'static' szó. Paraméterre nincs szükség - hiszen a példányszintű metódusok az adott példány mezőivel kell hogy dolgozzon. Ezeket a mezőket viszont direkt módon éri el.
  • A metódis védelmi szintjét jelen példában szintén 'public'-ra kell állítani, hiszen kívülről, a főprogramból fogjuk majd aktiválni.


Ismételten oldjuk meg a feladatokat, de ezúttal ezen metódus segítségével.

// Teglalap osztály kezelő főprogram
class Foprogram
{
    //..........................................................................
    public static void Main()
    {
        Teglalap t;
        t = new Teglalap();
        t.x = -20;
        t.y = +30;
        t.szelesseg = 10;
        t.magassag = 20;
        Console.WriteLine("A teglalap kerulete = {0}", t.kerulet());
    }
    //..........................................................................
}
  • a kerület metódus aktiválása a példányon keresztül történik: 't.kerulet()'.
// Teglalap osztály kezelése vektorban
class Foprogram
{
    //..........................................................................
    public static int Kerulet(Teglalap t)
    {
        return 2 * (t.szelesseg + t.magassag);
    }
    //..........................................................................
    public static void Main()
    {
        Teglalap[] tomb = new Teglalap[30];
        // --- rekordok létrehozása a memóriában ---
        for (int i = 0; i < tomb.Length; i++)
            tomb[i] = new Teglalap();
        // --- rekordok mezőinek feltöltése  ---
        Random rnd = new Random();
        foreach (Teglalap t in tomb)
        {
            t.x = rnd.Next(-100, 100);
            t.y = rnd.Next(-100, 100);
            t.szelesseg = rnd.Next(10, 100);
            t.magassag = rnd.Next(10, 100);
        }
        // --- maximális elem sorszámának kiválasztása ---
        int maxI = 0;
        for (int i = 1; i < tomb.Length; i++)
            if (tomb[i].kerulet() > tomb[maxI].kerulet())
                maxI = i;
        // --- kiírás ---
        Console.WriteLine("A teglalap adatai: X={0}, Y={1}, Szelesseg={2}, Magassag={3}",
            tomb[maxI].x,
            tomb[maxI].y,
            tomb[maxI].szelesseg,
            tomb[maxI].magassag
        );
    }
    //..........................................................................
}
  • a kerület metódus aktiválása a példányon keresztül történik: 'tomb[i].kerulet()'.
// Teglalap osztály kezelése listában
class Foprogram
{
    public static void Main()
    {
        ArrayList lista = new ArrayList();
        // --- rekordok létrehozása a memóriában ---
        for (int i = 0; i < 30; i++)
        {
            Teglalap t = new Teglalap();
            lista.Add( t );
        }
        // --- rekordok mezőinek feltöltése  ---
        Random rnd = new Random();
        foreach (Teglalap t in lista)
        {
            t.x = rnd.Next(-100, 100);
            t.y = rnd.Next(-100, 100);
            t.szelesseg = rnd.Next(10, 100);
            t.magassag = rnd.Next(10, 100);
        }
        // --- maximális elem sorszámának kiválasztása ---
        int maxI = 0;
        for (int i = 1; i < lista.Count; i++)
            if ((lista[i] as Teglalap).kerulet() > (lista[maxI] as Teglalap).kerulet())
                maxI = i;
        // --- kiírás ---
        Console.WriteLine("A teglalap adatai: X={0}, Y={1}, Szelesseg={2}, Magassag={3}",
            (lista[maxI] as Teglalap).x,
            (lista[maxI] as Teglalap).y,
            (lista[maxI] as Teglalap).szelesseg,
            (lista[maxI] as Teglalap).magassag
        );
    }
    //..........................................................................
}
  • a metódus aktiválása most is a példányon keresztül történik, de itt a példányt a lista típustalansága miatt először típuskényszeríteni kell: '(lista[i] as Teglalap).kerulet()', vagy használhatnánk a hagyományos alakot is: '((Teglalap)lista[i]).kerulet()'. Ekkor azonban bonyolultabb a zárójelezés.


// Teglalap osztály kezelése típusos listában
class Foprogram
{
    public static void Main()
    {
        List<Teglalap> lista = new List<Teglalap>();
        // --- rekordok létrehozása a memóriában ---
        for (int i = 0; i < 30; i++)
            lista.Add(new Teglalap());
        // --- rekordok mezőinek feltöltése  ---
        Random rnd = new Random();
        foreach (Teglalap t in lista)
        {
            t.x = rnd.Next(-100, 100);
            t.y = rnd.Next(-100, 100);
            t.szelesseg = rnd.Next(10, 100);
            t.magassag = rnd.Next(10, 100);
        }
        // --- maximális elem sorszámának kiválasztása ---
        int maxI = 0;
        for (int i = 1; i < lista.Count; i++)
            if (lista[i].kerulet() > lista[maxI].kerulet() )
                maxI = i;
        // --- kiírás ---
        Console.WriteLine("A teglalap adatai: X={0}, Y={1}, Szelesseg={2}, Magassag={3}",
            lista[maxI].x,
            lista[maxI].y,
            lista[maxI].szelesseg,
            lista[maxI].magassag
        );
    }
    //..........................................................................
}
  • a különbség csak abban van, hogy a metódushíváshoz sem kell a típuskényszerítést használni, mivel a lista elemeinek a típusa ismert a fordítóprogram által.

Szabályok a mezők értékeire - property

"Feladat": a téglalap mezőinek aktuális értékeire az alábbi megkötéseket tesszük:

  • a szélesség értéke nem nulla, vagy negatív számok
  • a magasság értéke nem nulla, vagy negatív számok
// Teglalap osztály kiegészítve property-kkel
class Teglalap
{
    //..........................................................................
    protected int _szelesseg;
    //..........................................................................
    public int szelesseg
    {
        get
        {
            return _szelesseg;
        }
        set
        {
            if (value <= 0) throw new Exception("Nem lehet negativ vagy nulla!");
            else _szelesseg = value;
        }
    }
    //..........................................................................
 
    //..........................................................................
    protected int _magassag;
    //..........................................................................
    public int magassag
    {
        get
        {
            return _magassag;
        }
        set
        {
            if (value <= 0) throw new Exception("Nem lehet negativ vagy nulla!");
            else _magassag = value;
        }
    }
    //..........................................................................
    public int x;
    public int y;
    //..........................................................................
    public int kerulet() 
    {
        return 2 * (szelesseg + magassag);
    }
    //..........................................................................
}
  • amennyiben valamely mezőre szabály, megszorítás van, úgy az nem lehet 'public'. Ez esetben ugyanis a külső kód direkt módon írhatná a mező értékét, és lehetősége lenne hibás érték beírására is.
  • a mező ilyenkor jellemzően 'protected' lesz, hogy a gyerekosztályok a mezőt képesek legyenek elérni direkt módon is (ez gyors kezelést tesz lehetővé). Csak nagyon indokolt esetben állítjuk a mezőt 'private'-ra.
  • az elrejtett mező nevét névadási hagyomány szerint megváltoztatjuk, és egy '_' karakterrel egészítjük ki.
  • a property neve így már megkaphatja az előbb használt, "szép" nevet.
  • a property get része jellemzően egyszerű, visszaadja a háttérben működő, de a külvilág számára nem elérhető mezőben lévő értéket
  • a property set részében a beírandó értéket a 'value' kulcsszó segítségével kapjuk meg
  • a property set része legegyszerűbb esetben is legalább egy 'if'-et tartalmaz, mely ellenőrzi, hogy a beírandó érték megfelelő-e. Amennyiben nem, kivétel feldobásával jelzi. Amennyiben az érték megfelelő, eltárolja az elrejtett mezőben.

Szabályok a mezők kezdőértékeire - konstruktor

Alkalmazzunk konstruktort a mezők kezdőértékének beállításához. Alkalmazzunk property-ket a mezők értékeinek kiolvasásához, beállításához, miközben a szóban forgó szabályok sérthetetlenségét biztosítjuk.

// Teglalap osztály interface kiegészítve a konstruktorral
class Teglalap
{
 protected int _szelesseg;
 protected int _magassag;
 public int x;
 public int y;
 public int keruletSzamitas() {...}
 
 public Teglalap(int szelesseg, int magassag, int x, int y) {...}
 public int szelesseg { get {...} set {...} }
 public int magassag  { get {...} set {...} }
}
// Teglalap osztály kidolgozása kiegészítve a konstruktorral
class Teglalap
{
    //..........................................................................
    protected int _szelesseg;
    //..........................................................................
    public int szelesseg
    {
        get
        {
            return _szelesseg;
        }
        set
        {
            if (value <= 0) throw new Exception("Nem lehet negativ vagy nulla!");
            else _szelesseg = value;
        }
    }
    //..........................................................................
 
    //..........................................................................
    protected int _magassag;
    //..........................................................................
    public int magassag
    {
        get
        {
            return _magassag;
        }
        set
        {
            if (value <= 0) throw new Exception("Nem lehet negativ vagy nulla!");
            else _magassag = value;
        }
    }
    //..........................................................................
    public int x;
    public int y;
    //..........................................................................
    public int kerulet() 
    {
        return 2 * (szelesseg + magassag);
    }
    //..........................................................................
    public Teglalap(int szelesseg, int magassag, int x, int y)
    {
        this.szelesseg = szelesseg;
        this.magassag = magassag;
        this.x = x;
        this.y = y;
    }
    //..........................................................................
}
  • a konstruktor írásakor ügyeljünk, hogy ha úgyanúgy nevezzük el a paraméterváltozókat, mint amilyen nevű mezőnk, vagy property-nk van, akkor a 'this' segítségével kell hangsúlyoznunk, mikor gondolunk a property-re.
  • a konstruktor a property-n keresztül menti el a paraméterben megkapott kezdőértékeket, mivel így az keresztülmegy a property ellenőrző mechanizmusán.
  • a konstruktor biztosítja, hogy a mezők kezdőértéket kapjanak a példányosításkor. A property ugyanis csak a már létrehozott példányok esetén működik, nem garantálja önnmagában, hogy a példány létrehozásakor a mezők kezdőértéke eleve helyes lesz.
A lap eredeti címe: „http://wiki.ektf.hu/wiki/Mp4/page01
Nézetek
nincs sb_18.222.240.21 cikk