A J# programozási nyelv

Típusok, típuskonstrukciók



Típusok, típuskonstrukciók

Típusszerkezet

Mivel a J# a Java nyelv specifikációját valósítja meg, így megörökölte annak típusrendszerét is. Két féle típus van. Az egyik az elemi típus, a másik a referencia típus. Azonban a Visual J# fordító lehetővé teszi, hogy használjuk a .NET Framework-ben definiált érték típusokat is, vagy amiket más felhasználó definiált egy külső assembly-ben.

Elemi típusok

Fajtái:

Elemi típusok jellemzői:

Referencia típusok

Minden típus ami nem elemi típus, az referencia típus. Ezek nem mások, mint az objektumok.
Bővebben lásd az Objektum-orientált programozás c. fejezetben.

Referencia típusok jellemzői:

Függvénypointer típusok

A Visual J# fordító engedélyezi delegate-ek (függvény-pointerek) létrehozását. Fontos, hogy a kötés fordítási időben történik. A delegate típus deklarációjának a következő komponensekből áll:

/** @delegate */ public delegate void EventHandler();

Delegate kezelő definiálása

J#-ban a delegate tí­pus referencia típus. A referencia tí­pus definiálása 2 részből áll:

Proc p1;

p1 jelenti a Proc delegate típus delegate objektumának kezelőjét, nem a delegate objektumot.

Egy delegate objektum meghatározása

Nézzük az alábbi osztályokat

public class MyDateClass { public void DisplayDate() { Date dt = new Date(); System.out.println("The date is: " + dt.getDate()); } } public class MyTimeClass { public static void DisplayTime() { Date dt = new Date(); System.out.println("The time is: " + dt.getHours() + 'h' + ' ' + dt.getMinutes() + 'm');
Ahhoz, hogy a p1-et a MyDateClass DisplayDate metódusához kössük, a Proc delegate típusból új példányt kell létrehoznunk a new operátorral. A konstruktor paramétere az a név, amelyet az objektum és metódus nevének a ’.’ operátorral való összefűzésével kapunk.

MyDateClass d = new MyDateClass(); Proc p1 = new Proc(d.DisplayDate); p1 = new Proc(MyTimeClass.DisplayTime);

Multicast delegate

Az összetett delegate-eket összefűzhetjük multicast(csoport) delegate-kké A System.Delegate típus két metódust támogat a multicats delegate-k kezelésére: Combine és Remove. Nézzük meg az alábbi delegate objektum a MyTimeClass DisplayTime metódusát címzi meg.

Proc p2 = new Proc(MyTimeClass.DisplayTime);

Most a p1 és p2 delegate-ket kombinálhatjuk:

Proc p3 = (Proc) System.Delegate.Combine(p1, p2);

A p3 egy delegate lánc. A p3.Invoke() metódus hívása a p1 és p2 Invoke() metódusát hívja meg(ebben a sorrendben). A System.Delegate.Remove metódus lehetővé teszti delegate eltávolítását a delegate láncból.

A fordító delegate támogatása

Az alábbi metódus egy delegate típust definiál:

/** @delegate */ public delegate void Proc();

Amikor a J# fordító ehhez a két sorhoz ér, egy teljes osztály definíciót ad:

Az eredmény IL-ben:

.class public auto ansi sealed Proc extends [mscorlib]System.MulticastDelegate { .method public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed { } // end of method Proc::.ctor .method public hidebysig strict virtual instance void Invoke() runtime managed { } // end of method Proc::Invoke .method public hidebysig newslot strict virtual instance class [mscorlib]System.IAsyncResult BeginInvoke(class [mscorlib]System.AsyncCallback callback, object 'object') runtime managed { } // end of method Proc::BeginInvoke .method public hidebysig newslot strict virtual instance void EndInvoke( class [mscorlib]System.IAsyncResult result) runtime managed { } // end of method Proc::EndInvoke } // end of class Proc

Az alábbi kód lefoglalja a delegate objektumot és meghívja a konstruktort:

p1 = new Proc(MyTimeClass.DisplayTime);

Az eredmény IL-ben :

... IL_000b: ldftn void MyTimeClass::DisplayTime() IL_0011: newobj instance void Proc::.ctor(object, native int) ...

Az alábbi kód végrehajtja a delegate-t:

p1.Invoke();

IL-ben az eredmény:

callvirt instance retType DelegateClass::Invoke( )

Típus ekvivalencia

A delegate név-ekvivalenciát támogat. Két különböző delegate típus, amelyeknek ugyanazok a paraméterei és a visszatérési értéke, következésképpen különböző delegate típusok.

Vezessünk be egy új delegate-t:

/** @delegate */ public delegate void Proc2; Proc2 p2 = new Proc2(MyTimeClass.DisplayTime); if (p1 == p2) ... // Fordítás idejű hiba ;

P1 és P2 különböző típusúak.

Ahhoz, hogy ellenőrizzük, hogy a két delegate ugyanazokat a metódusokat tartalmazza, az equals metódust kell használnunk:

if (p1.equals(p2)) ... // Ok

Típuskonstrukciók

Mivel a nyelv objektum orientált, ezért a típuskonstrukció elsődleges eszköze az objektum (lásd az Objektum-orientált programozás c. fejezetet). De van néhány más lehetőség is. Ilyen a tömb és a felsorolási típus.

Tömb

Sok azonos típusú elemek tárolására használható. Valójában a tömb is referencia típusú. Így tehát a tömbváltozó létrehozása nem hozza létre a tömböt, hanem azt külön létre kell létrehozni, és hozzákötni a tömbváltozóhoz.

Előnye:

Hátránya: Indexelés: tömbváltozó[index]

Hossz lekérdezése: tömbváltozó.length

int[] t = new int[3] {0,1,2}; t[0] = t[1] + t.length;

Felsorolási típus

A J# támogatja egyedi felsorolási típusok definiálását. A felsorolási típusok, speciális érték-típusok. Egy felsorolási típus valójában egy int ahol a megfelelő nevek meg vannak feleltetve a számoknak.

Deklarációja hasonló az osztály deklarációhoz, a következő kivételekkel:

public enum ColorEnum { Red, Green, Blue }

Egy felsorolási elem értékét lehet cast-olni:

int i = (int) ColorEnum.Red

Ha egy felsorolási értéket a new kulcsszóval akarunk használni, akkor ez hibához vezet.

Az egész értékét egy felsorolási típus egy tagjának a következő szintaxissal lehet megadni:

public enum ColorEnum { Red(1), Green(2), Blue(3) }

Ha ezeket az értékeket nem adjuk meg explicit, akkor ezeket a fordító beállítja, a legelső elemnek 0-t, majd az összes többinek az előzőnek a rákövetkezőjét.

public enum ColorEnum { Red, Green(10), Blue }

Itt a Red a 0 értéket, a Green a 10-et, a Blue pedig a 11-et kapja.

A többszörös felsorolási típusokban meg lehet osztani az azonos egész értékeket.

Egy felsorolási típusban a tagok egymástól való függősége engedélyezett, kivéve a ciklikus függés.

public enum ColorEnum { Red, Blue, Green(Blue); }

Az implicit típuskonverzió nem megengedett, csak cast-olással lehet konvertálni.

int i = Color.Red; // error int i = (int) Color.Red; // OK

A következő operátorokat lehet használni a felsorolási típus értékeinek összehasonlítására: ==, !=, <, >, <=, >=, +, -, ^, &, |, ~
Leggyakoribb használatuk: switch szakaszban:

ColorEnum color = Color.Red; switch( color ) { case ColorEnum.Red: // ... break; case ColorEnum.Blue: // ... break; case ColorEnum.Green: //... break; default: break; }

Típuskonverziók

Referencia típus esetében a felfelé cast-olás (upcast) automatikusan megtörténik, ha erre szükség van. A lefelé cast-olást (downcast) explicit módon kényszeríthetjük ki. Ez hasonló módon történik J#-ban, mint azt a C/C++ nyelvekben megszokhattuk. A változó elé zárójelbe írt típusnév hatására a változó tartalma a megadott típusra konvertálódik, amennyiben a konverzió lehetséges. Ezt érték típusú változók esetén is megtehetjük.

int i = 10; double d = (double)i;

Egy érték-típusra irányuló kérés lehet közvetlenül, mint egy Object-re. A Visual J# fordító implicit elvégzi a szükséges box-olást(bedobozolást), amikor az értékből objektum lesz. Hasonlóan a "kidobozolást" vagy cast-olást is elvégzi a fordító automatikusan.

Változók, konstansok

Változókat a következő szintaxissal deklarálhatunk:

    láthatóság módosítók 
    típus változónév [= <kifejezés>] (, változónév [= <kifejezés>])*;
Ahol:
public int i, j = 10, k = i+j*2; private const double d = (double)i;

Kifejezések, operátorok

Egy kifejezés vagy aritmetikai, vagy logikai. Ez attól függ, hogy mi az utoljára végrehajtott művelet eredménye. Ha a kifejezés elmarad, akkor üres utasításról beszélünk (;) (lásd a Utasítások, vezérlési szerkezetek c. fejezetet)

Az értékadás is egy kifejezés. Ennek operátorai: =, +=, -= *=, /=, ++, --
(lásd a Utasítások, vezérlési szerkezetek c. fejezetet)

Operátorok: