Q: Exception design questions
janderson
askme at me.com
Sat Jun 16 13:57:54 PDT 2007
Myron Alexander wrote:
> Hello.
>
> I am struggling with creating an exception design for my library. I have
> written libraries and exception mechanisms before but those libraries
> were focused on a core problem for which all use-cases are known
> upfront. With this library, because it is distributed, I am not in
> control of how it is used so I am struggling to envision all possibilities.
>
> What I have decided is to restrict the number of exceptions to just
> those that either define a domain or declare a specific recoverable
> exception. For my library, there will be very few recoverables, mostly
> to do with data conflicts and database locks.
>
> I am of the type that, as a library/framework architect, tries to
> provide the most information possible to the developer such that the
> developer is able to quickly pinpoint the problem and resolve it.
>
> With that in mind, I needed a flexible exception class that could handle
> all the information known about the state at the time of the exception.
> I decided on a property bag that will hold all the information as
> properties.
>
> This is what I came up with:
>
>> public class SqlException : Exception {
>>
>> this (char[] msg) {
>> super (msg);
>> }
>>
>> typeof(this) setSql (char[] sql) {
>> m_propertyBag[K_SQL] = box (sql);
>> return this;
>> }
>>
>> typeof(this) setProperty(T) (char[] property, T value) {
>> m_propertyBag [property] = box (value);
>> return this;
>> }
>>
>> void raise () {
>> throw this;
>> }
>>
>> char[] toString () {
>>
>> /* Format properties for output. The properties are listed one
>> to a line
>> * of format 'name: value'.
>> */
>> char[] pstr;
>>
>> foreach (p; m_propertyBag.keys.sort) {
>> pstr ~= "\n" ~ p ~ ": " ~ m_propertyBag[p].toString ();
>> }
>>
>> if (pstr.length > 0) {
>> return msg ~ "\n" ~ pstr;
>>
>> } else {
>> return msg;
>> }
>> }
>>
>> char[] sql () {
>> if (K_SQL in m_propertyBag) {
>> return unbox!(char[])(m_propertyBag[K_SQL]);
>>
>> } else {
>> return null;
>> }
>> }
>>
>> Box[char[]] propertyBag () {
>> return m_propertyBag;
>> }
>>
>> protected Box[char[]] m_propertyBag;
>> private static const final K_SQL = "SQL";
>> }
>
> And this is how I use it:
>
>> (new SqlProgrammingException (
>> "Invalid bind type. Mixing single and multiple value rows. "
>> "The first argument type is other than Box[], thus it is "
>> "assumed that the rest of the arguments are single value "
>> "rows."))
>> .setSql (operation)
>> .setProperty ("ValueRow", i)
>> .setProperty ("ValueType", t)
>> .raise ();
>
> which outputs:
>
>> Error: Invalid bind type. Mixing single and multiple value rows. The
>> first
>> argument type is other than Box[], thus it is assumed that the rest of
>> the
>> arguments are single value rows.
>>
>> SQL: insert into atable values (?,?,?)
>> ValueRow: 1
>> ValueType: std.boxer.Box[]
>
> My questions are:
>
> 1. Is there a better way to design the exceptions?
> 2. If you have experience with this style what shortcomings did you notice.
> 3. Is there anything I have missed (conceptually or practically)?
> 4. Is there anything I should remove, or add?
>
> Thanks ahead,
>
> Myron.
Personally I'd try to put all those sets in the constructor, then u
don't need to expose these to the catcher of the exception.
-Joel
More information about the Digitalmars-d
mailing list