Ahhoz képest, hogy ennyire rossz, elég olvasott. Csak nem lapulnak Delphi fejlesztők is köztünk? 😀 Most egy natív/menedzselt összehasonlítás következik, még mielőtt valami hittérítőnek titulálnának itt engem a C# “fanszőrök”. Egyébként meg, aki a Delphi 1.0 compiler-t tervezte, az tervezte a C#-ot is, ha már okulni kell valamiből, hogy honnan lett egy kismillió fícsör csincselve (Íme Anders Heijlsberg bátyánk története, aki még nem ismerné esetleg).
Delphi | Delphi Prism |
---|---|
Korábbi Delphi változatokban az alapértelmezett string az AnsiString volt. Jelenleg már a natív Delphi 16 bites unicode string-et használ alapértelmezésben. Ellenben a .NET-es stringel, a natív Delphi string változtatható, index alapján a karakterek lekérdezhetők és módosíthatók, viszont nem zero alapúak. Az első karakter indexe: 1. Két fajta string is van (ShortString (max. 255 karakter), LongString), de a 32 bites Delphi óta a string = LongString. A natív Delphi stringek referencia számláltak. A compiler belsőleg a Windows API/COM hívások megkönnyítésére támogatja a stringek PChar, PWideChar, illetve WideString típusokká történő kasztolását. Delphiben nincs nil string, vagy üres string van, vagy nem. A string hosszát ugyanúgy egy beépített Length() függvény adja vissza.
A Delphi RTL viszonylag elég sok string művelettel kapcsolatos függvényt definiál, névben szinte teljesen azonos a .NET String osztály metódusainak nevével. |
A string kulcszó (típus alias) .NET-ben a System.String típust jelöli. .NET-ben a string típus egy 16 bites unicode string. A stringek csak olvasható adattípusok, nem módosíthatók. A string szolgáltat egy alapértelmezett indexer tulajdonságot, engedve hozzáférni minden egyes karakterhez (de csak olvasható). Az index zero alapú (mint minden FCL metódus, amely stringekkel dolgozik). A .NET különbséget tesz egy nil string és egy üres (zero-hosszúságú) string között. Fájdalommentessé téve ezt, a compiler rendelkezésre bocsájt egy length() intrinsic függvényt, amely 0-át ad vissza abban az esetben, ha a referencia nil, vagy ha ténylegesen nulla hosszúságú a string. .NET-ben a string lehetővé teszi ezt az ellenőrzést egy statikus metódus által is:
if (s <> nil) and (s <> '') then //... if length(s) > 0 then //... if not String.IsNullOrEmpty(s) then // ... A String osztály viszonylag sok taggal szolgál a tipikus string műveletek teljesítéséhez, úgy mint: Pos, Copy, stb. Mivel a stringek csak olvashatók, ezek a metódusok generálni fognak egy új string példányt visszatérési értékként. Tehát a string egy immutable (megváltoztathatlan) típus. A System.Text.StringBuilder osztály használható elérni a változtathatóságot, és erősen ajánlott is hasznáni azt, elkerülve a sok konkatenáció műveletet a ‘+’ operátor által. Persze ez se vehető mindig kézpénznek, érdemes megvizsgálni a kódot, hogy éppen mi a hatékonyabb. |
A Delphi a megszorításokat a generikus típusdefiníció részeként definiálja.
type TStack<T, U: class; V: constructor; Z: IEnumerable<T>> = class Ezzel van is problémám: 1. Curiously recurring template pattern (Nem lehet definiálni rekurzív generikus típusokat) TMyClass<TA, TB: TA> = class end; // Ez okés. TMyClass<TA: TB, TB> = class end; // Ez nem okés. |
A Delphi Prism a where kulccszót használja generikus megszorítások definiálására.
type TStack<T, U, V, Z> = class where U is class, V has constructor, Z is IEnumerable<T>; |
resourcestring RES_APPLICATION_TITLE = ‘My Application’; |
A Delphi Prism nem támogatja a resourcestring nyelvi fícsört. |
procedure és function kulcsszavak | A Delphi Prism visszafele kompatibilitást ajánl ezekhez a kulcsszavakhoz, de bevezet egy új method kulcsszót is, függetlenül attól, hogy van-e visszatérési értéke a metódusnak, avagy nincs. Ajánlott használni az új kulcsszót minden újonnan írt kódhoz. |
A Delphi támogatja az elnevezett konstruktorokat, más kérdés, hogy nem tanácsolt a használata, mert a C++Builder azokkal nem tud mit kezdeni. A natív Delphiben létezik a virtuális konstruktor fogalma. Ezekre nincs szükség .NET-ben, mivel a CLR automatikusan kikényszeríti az örökölt konstruktor hívást még mielőtt bármihez is hozzá lehetne nyúlni. | A .NET runtime nem támogatja az elnevezett konstruktorokat és a Delphi Prism emiatt szintén kikényszeríti a névtelen konstruktor szintaxist. Ugyan megengedett kírni a Create-et a constructor kulcsszó után, de nincs hatással a generált kódra. A konstrukorok egyedien azonosítottak kell legyenek a paramétereik által.
Továbbá, a CLR-nek szükséges, hogy minden konstruktor meghívjon egy másik konstruktort, ami definiált ugyanabban az osztályban, vagy egy bázis osztályban, pontosan egyszer, mielőtt engedne hozzáférni a Self (this), vagy bármelyik tagjához a típusnak. Ahol szükséges, a Delphi Prism automatikusan befogja szúrni a hívásokat az örökölt konstruktorokra. |
A Delphi nem GC alapú nyelv, így szükség van destruktorokra, amelyben a lefoglalt erőforrásokat fel kell szabadítani. Ugyanakor a Delphi támogat egy tulajdonos patternt, ami lehetővé teszi, hogy egy tulajdonosra (Owner) bízzuk az objektum megsemmisítését. Minden TComponent osztály rendelkezik ezzel az Owner property-vel, illetve alapértelmezésben minden TComponent származék konstruktora magába foglalja ezt paraméterként, mint pl. egy sima form is:
TMyForm.Create(Application).Show; |
A Delphi Prism nem támogat destruktorokat, vagy a destructor kulcsszót. Ez a koncepció nem létezik a CLR-ben. Legtöbb esetben az osztályok tisztán menedzseltek és nincs szükség speciális kódra felszabadítani, vagy megsemmisíteni őket. Osztályok, melyek használnak unmanaged erőforrásokat (úgy mint fájl kezelők) és szükséges determinisztikus megsemmisítés, a runtime szolgál kétfajta koncepcióval, melyek teljesen támogatottak a Prism által is.
– Az egyik az IDisposable interfész megvalósítása, amely a Dispose pattern megvalósítása a .NET-ben, így lehetővé téve az objektumoknak, hogy engedjék el az unmanaged erőforrásokat. Néhány helyen ezt az FCL osztályok implementálják és elvárják, hogy illően legyenek felszabadítva. A könnyű használatot elősegítve használható a using kulcsszó. – Finalizers: szolgáltat egy visszacsatolási mechanizmust megtisztítani osztályokat, amik nem lettek illően felszabadítottak. Ezek költségesek a GC-nek (előfordulhat, hogy egy objektumnak többször is át kell mennie a szemétgyűjtésen), emiatt csak abban az esetben kellene alkalmazni őket, ha tényleg szükséges. Delphi Prism alternatíva a FreeAndNil() függvényre a DisposeAndNil(), amely ekvivalens a következővel: if Assigned(AnObject) and (AnObject is IDisposable) then AnObject.Dispose; AnObject := nil; |
Delphiben lehetőség van inicializálni és megsemmisíteni erőforrásokat az alkalmazás betöltésekor, illetve kilépéskor. Erre szolgál az initialization, illetve finalization szekció. | A Delphi Prism nem támogatja az initialization és finalization szekciókat, mert ez a koncepció nem létezik a .NET-ben és a CLR-ben. Az inicializáció osztály-konstruktorokkal (statikus konstruktorokkal) szintén elérhető. |
Delphiben az események alapvetően tulajdonságai a típus metódus pointernek és csak egy kezelőjük lehet. | A .NET másfajta esemény modelt használ, mint a Delphi. Delphi Prismben az események különálló típusai az osztálytagoknak, amik definiáltak az event kulcsszó által. Az események a delegatektől (multi-cast delegates) függnek, definiálják a szignatúráját az eseménynek, amelyeket ők reprezentálnak, illetve karbantartják egy listáját a feliratkozottaknak. További részletek itt. |
A Delphi támogatja sima konstansokat, melyek állandóak:
const A = 10;
Illetve támogat ún. tipizált konstansokat, melyek módosíthatók, viszont függvényen belül deklarálva is megtartják az értéküket (emlékeim szerint, C/C++-ban static változók): const A: Integer = 10;
|
A Delphi Prism két helyen alkalmazza a sztenderd Pascal hozzárendelő operátort, ahol a Delphi sima ‘=’ operátort használ.
1. Default értékei a metódus paramétereknek: method Foo(a: Integer; b: string := 'default') Az oka ennek az, hogy ez jobban szemlélteti azt, hogy itt tényleg egy hozzárendelés történik, nem pedig egyezőség vizsgálat. 2. Hasonlóan, a mezők is lehetnek előinicializáltak. myField: Integer := 5 Nem keverendő össze a natív tipizált konstansokkal (const A: Integer = 10), ahol az érték később is változtatható. Prismben sima konstansok vannak csak, amelyek csak olvashatók. |
A Delphi teljes mértékben támogatja a pointer aritmetikát: További részletek itt. | Mint menedzselt környezet, a .NET és a CLR limitált támogatással szolgál a pointerekhez, illetve memória manipulációhoz. Általában ez nem probléma, és a legtöbb kód ami pointerekre hagyatkozik újraírt lehet teljesen menedzselt kódban, ellenőrizhetően, egy kisebb erőfeszítéssel. Ez az ajánlott megközelítés.
Bárhogy is legyen, a CLR és a Delphi Prism támogatja unsafe kód beágyazását, megjelölve egy metódust az unsafe direktívával. A nem biztonságos nem jelenti azt, hogy eredendően rossz a kód vagy hibás, csak azt, hogy memória műveleteket végezhet, amik nem ellenőrizhetők, mint “bizonságos kód” a runtime által. |
A Delphi enged beágyazni inline assembly kódot. | A Delphi Prism IL kódot generál, nem x86, vagy valamilyen CPU specifikus kódot, így nincs támogatás asm betétek készítéséhez. |
A Delphi az ‘=’ operátort használja, hogy implementáljon interfész metódusokat különböző néven, elkerülve a névütközéseket.
procedure MyFooBar; procedure IFoo.bar = MyFooBar; // Maps the MyFooBar method to the IFoo interface. |
A Delphi Prism nem szolgált szintaxissal ehhez, de használja az implements kulcsszót, hogy elérje ugyanezt, illetve sokkal több flexibilitással szolgál a folyamatban. További részletek itt. |
Delphiben minden ‘/’ általi osztás művelet egy lebegőpontos értéket ad vissza. A div operátor használt az egész osztáshoz. | A viselkedése a ‘/’ operátornak különbözik a Delphitől abban, hogy a Prism kikövetkezteti az eredmény típust a két operandusoból. Inkább, minthogy állandóan floating point típust használjon visszatérésként => Két egész érték osztása egy kerekített egésszé fog válni. |
private A szimplán privát tagok láthatók ugyanazon osztályon, de a uniton (egy forrás fájlon) belüli egyéb osztályok számára is. strict private protected strict protected public published |
private Különbözik a Delphitől. A privát tagok láthatóak csak ugyanazon az osztályon belül, de más osztályon belül ugyanabban a forrás modulban nem. Ez összehasonlítható a Delphi strict private láthatóságával. protected assembly and private assembly assembly and protected public |
A Delphi csak a konstansokat engedi kód blokkban inicializálni (a Prism nem engedi ezt):
const p: TPoint = (x: 15; y : 16);
|
A Delphi Prism használ elnevezett paramétereket inicializálni egy rekordot (struct) vagy osztályt.
var x := new MyRecord(Field1 := 'test', Field2 := 15.2); |
A Delphi támogatja a megjelölését egy unitnak, egy metódusnak, vagy sima globális függvények/eljárásnak, mint deprecated. A compiler erről egy figyelmeztető üzenetben tájékoztat.
procedure TestMethod; deprecated; |
A Delphi Prism nem támogatja a deprecated tag direktívát, de az obselete attribútum hasonló:
[Obsolete] method TestMethod; |
Röviden ennyi. Van rengeteg dolog ami ugye nincsen natív Delphibe, mint pl. típuskövetkeztetés, lambdák, LINQ, de még inline deklarált változók sem.