Aszinkron metódushívások
Mit tegyünk, ha bizonyos programrészeket párhuzamosan szeretnénk futtatni, de nem akarunk többszálú program megírásával vesződni? Mit tegyünk, hogy ha nem akarjuk, hogy egy hosszabb ideig tartó metódushívás blokkolja a programunkat? A fentiekre választ kaphattok az alábbiakban.
Normál esetben egy metódus meghívásakor az eredeti programrészlet futása megszakad, a metódus kódja lefut és visszatérünk a hívás helyére. Ameddig tehát tart a metódus kódjának futása, addig blokkolódik az eredeti és ez sokszor nem kívánatos. Legyen például egy alkalmazásunk, amely netről tölt le fájlokat és dolgozza fel őket. Egy ciklussal végigmegyünk az URL-ek gyűjteményén, kiépítjük a kapcsolatot, letöltjük a fájlt, majd feldolgozzuk egy megfelelő függvénnyel. A fenti megoldás hátránya, hogy a letöltés időtartama alatt nem tudunk foglalkozni a már letöltött tartalmakkal. Javíthatjuk a programot úgy, hogy a letöltést külön programszál végezze, így a feldolgozó függvény a letöltésekkel párhuzamosan dolgozhat. A többszálú programok fejlesztése meglehetősen körülményes, nehéz a hibákat felderíteni és kijavítani, és kiemelt figyelmet kell fordítanunk a szálak közötti szinkronizációra.
A fenti programot megírhatjuk explicit szálkezelés nélkül is: a .Net lehetőséget biztosít arra, hogy a megírt tagfüggvényeinket aszinkron módon is meghívhassuk, mégpedig delegate-ek, azaz metódusreferenciák segítségével. Metódusreferenciák formájában függvényeket paraméterek formájában is átadhatunk, majd ott meghívhatjuk őket (lásd C++ funktorok). Egy metódusreferencián keresztül egy neki megfelelő szignatúrájú függvényt tudunk visszahívni.
A példában egy string visszatérési értékkel és egy string paraméterrel rendelkező metódussal példányosítható a delegate. A háttérben a rendszer a deklaráció alapján egy megfelelő osztályt generál, amely segítségével a különböző típusú hívásokat végre tudjuk hajtani. Az Invoke(…) hatására normál módon hívhatunk, a kód a fő szálon fut le, a metódus szignatúrája megegyezik a metódusreferencia által várttal. Aszinkron módon a BeginInvoke/EndInvoke párossal hívhatunk, ekkor a példában a Download kódja egy külön szálon fut. A BeginInvoke már nem blokkol, illetve csak annyi ideig, amennyi a másik szál elindításához szükséges. Az aszinkron hívás eredményét lekérhetjük az EndInvoke segítségével, illetve feldolgozhatjuk egy másik függvénnyel.