Mit előlegként
már megkaptál, ne várd a
végelszámolásnál.
Ahogy minden szoftverfejlesztőt, most éppen engem is utolért a végzet. Egy régebben C#-ban mások által megírt kódban kellett ad-hoc javítgatni egyet s mást, többek között egy el nem kapott exceptiont kellett valahogyan ártalmatlanná tenni. A probléma gyökere egy aszinkron függvényhívás mélyén rejtőzött, ahol az XML értelemző próbálta egy exceptionben a tudomásunkra hozni nemtetszését számunkra megfejthetetlen okból.
Mivel jobb ötletünk nem volt és a kód eredeti struktúrája is ezt sugallta, szépen beleraktunk egy újabb catch blokkot az BeginInvoke-ot övező catch mögé, amint ez a lentebb mellékelt részleten is látszik piros színnel kiemelve és ez remekül megoldotta a problémát.
public void AsynchCallFunc()
{
MethodDelegate dlgt = new MethodDelegate (this.AsynchCalledMethod) ;
string s ;
int iExecThread;
AsyncCallback cb = new AsyncCallback(MyAsyncCallback);
try {
IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, cb, dlgt);
}
catch (IOException ioe){
MessageBox.Show ("file not found");
}
// utólag hozzáadva az ismeretlen eredetű exception elkapására
catch (Exception e){
MessageBox.Show ("unknown error"); }
}
Elszállás eltűnt és minden náttyon jó és minden náttyon szép volt, mindennel meg voltunk elégedve, ahogy Ferenc Jóska mondta volna. Csakhogy egy-két nap múlva kiderült, hogy egyúttal néhány igencsak szükséges konfigurációs hibajelzés is eltűnt a sülyesztőben.MInt később kiderült azért, mert az a kivételeket valamiért két szinten kezelte az eredeti szerző. Egy részüket a BeginInvoke-ot , egy másik részüket pedig az EndInvoke-ot övező try-catch-ben. A dokumentáció szerint és ezt az amatőr versenyző (mármint én) el is hitte, hogy az EndInvoke-nál a szál futása során felgyűlt összes kivételt megkapja a hívó. És ez igaz is, de csak akkor, ha a BeginInvoke-nál nincs hibakezelés és nem kap el az ember semmilyen exceptiont. Mert azokat a kivételeket, amiket az ember begyűjtött a BeginInvoke-nál már nem fogja megkapni az EndInvoke során. Mivel mi az EndInvoke-nál elkaptuk típusspecifikáció nélkül az összes exceptiont, hiába állt az EndInvoke után egy tucat catch a különféle exception-ök kezelésére, amint a mellékelt kódban, mert ezeknél már sohasem érkezett egyetlen kivétel sem. public void MyAsyncCallback(IAsyncResult ar)
{
string s ;
int iExecThread ;
MethodDelegate dlgt = (MethodDelegate) ar.AsyncState;
try {
s = dlgt.EndInvoke (out iExecThread, ar) ;
} catch (IOException ioe){
MessageBox.Show ("file not found");
} catch (XMLProcessingError xmle){
MessageBox.Show ("XML error");
} catch (ConfigValueEXception cve){
MessageBox.Show ("configuration error");
}
}
Mivel a BeginInvoke is dobhat kivételt, ha valamilyen okból a végrehajtószálat nem tudja elindítani, a legegyszerűbb megközelítés az, ha valóban elkapunk minden exceptiont és a számunkra ismeretleneket továbbdobjuk. Ezeket a továbbdobott exception-öket majd módjában áll az EndInvoke hibakezelőjének tetszése szerint kezelni. A BeginInvoke/EndInvoke párosról többet itt lehet olvasni.
Piszkos Thread, a kapitány