Kód fejlesztése közben adódhat a szituáció, hogy a beépített kivételosztályok közül egy sem specifikálja igazán a probléma jellegét, amit le szeretnénk kezelni egy kivétel dobásával. Ebben az esetben célszerű egy saját típusú kivételt bevezetni. Ez nem bonyolult feladat, de néhány dologra ügyelni kell.
A saját kivételosztályunknak elnevezés szempontjából követnie kell a .NET keretrendszer nevezéktanát. Ez azt jelenti, hogy mint minden Exception osztálynak, a sajátunknak is Exception taggal kell végződnie, jelezve, hogy kivételosztályról beszélünk és nem egy szokványos osztályról.
Ahhoz, hogy a throw szintaxissal használható legyen, ennek az osztálynak az Exception ősosztályból kell öröklődnie. Gondolhatnánk, hogy ezzel kész is a feladatunk. A helyzet az, hogy nem teljesen.
public class MyException : Exception
{
}
Ugyan a kód fordul és a throw kulcsszóval tudjuk dobni a kivételt, de ezért az implementációs megoldásért egy valamire való statikus kód analizátor hibát dob. Mégpedig azért, mert megfelelő konstruktorok hiányában nem kompatibilis a többi Exception osztállyal. Ez azért problémás, mert ha Exception osztályokról beszélünk, akkor a fejlesztő, vagy a kódunk felhasználója jogosan feltételezi, hogy ez a többi kivételosztályhoz hasonlóan példányosítható.
Éppen ezért le kell implementálnunk minden saját kivétel esetén:
- Egy paraméter nélküli konstruktort
- Egy olyan konstruktort, ami egy
stringparamétert vár, ami meghatározza a kivétel szövegét. - Egy olyan konstruktort, ami egy
stringés egyExceptionparamétert vár.
Utóbbi konstruktor azért szükséges, hogy kivételeket újracsomagolva tovább tudjunk dobni, valami relevánsabb információval, ha szükséges.
Ezeket a konstruktorokat a Visual Studio segítségével könnyen kigenerálhatjuk. Álljunk a saját kivételosztályunk nevére, majd a CTRL + . hatására megjelenő menüben válasszuk a "Generate exception constuctors" menüpontot.
Ez létrehozza a szükséges konstruktorokat. Ezen felül természetesen készíthetünk saját, specifikusabb konstruktorokat is. Eddig a kódunk így néz ki:
public class MyException : Exception
{
public MyException() : base()
{
}
public MyException(string message) : base(message)
{
}
public MyException(string message, Exception innerException) : base(message, innerException)
{
}
}
Ez már majdnem jó, de még egy apróság hiányzik, méghozzá a Serializable attribútum a kivételosztályon. Ennek okai a .NET 1.0-ban keresendőek, meg még abban az időben, amikor a bináris szerializáció támogatott volt. Az ős kivételosztály szerializálható, akár binárisan is, ezért az összes leszármazottjának is szerializálhatónak kell lennie.
Ha ezt elmulasztjuk, akkor ezért szintén valószínűleg szólni fog egy statikus kódelemző. A végleges, helyes implementáció tehát a következő:
[Serializable]
public class MyException : Exception
{
public MyException() : base()
{
}
public MyException(string message) : base(message)
{
}
public MyException(string message, Exception innerException) : base(message, innerException)
{
}
}