views:

71

answers:

2

So, I'm stuck on a little problem. I was curious if anyone had some extra input they might be willing to give on this design.

I have an ILog interface which has two methods exposed for the Error Code logging part of the design. FlagError and GetErrorCode; FlagError sets a bit on an integer, each bit representing that a certain error was thrown., GetErrorCode (which would be the return value for the Main method) returns that said integer.

I speculated at first at using an enum in each application to contain a list of possible ErrorCodes.

But the problem is, how exactly would I relay to the users that error code 'XYZ' represents that the application hit these un-normal states during execution in a friendly way?

ILog Interface: (Write Methods have overloads)

interface ILog
{
    void FlagError (int errorCode);
    int GetErrorCode ();

    #region Other ILog Methods

    void WriteError(string  message);
    void WriteWarning(string  message);
    void WriteInfo(string  message);
    void WriteDebug(string  message);

    #endregion
}

Log Class:

abstract class Log : ILog
{
    public void
    FlagError (int errorCode)
    {
        if (errorCode == 0 || errorCode == int.MinValue || errorCode != (errorCode & -errorCode))
        {
            throw new IndexOutOfRangeException ();
        }

        if ((m_errorCode & errorCode) == errorCode)
             return;

        m_errorCode += errorCode;
    }

    public int
    GetErrorCode ()
    {
        return m_errorCode;
    } 


    #region Other ILog Methods    

}

I speculated using an attribute on each enum value with a description of that error, and then just having a little process or something to help 'parse' the error code into a human readable description.

But Idk, any Ideas?

A: 

I would probably go with the enum, placing those values and the logging code into a common Assembly that can be called by each application. It might not be the most elegant solution ever, but it gets the job done and let's you move on to more important things -- like good core business logic that doesn't throw too many errors :-).

Another option might be to put the error codes and human-readable descriptions into a config file. That way you would have some flexibility for improving the error messages. I've never tried that, but now that I think of it, I can see it being a real boon in many situations.

sfuqua
I like the idea of having human readable descriptions in a config file or something, but that's hard to maintain because I can't guarantee that if a developer adds a new error code they will go back and alter the config file. I am looking for a way that is obvious to developers and easy to interpret for the user.
Meiscooldude
+2  A: 

Thanks for your comments guys, I took them into consideration, and found a solution that (while not the best) will work for what I need done.

I ended up created a Description attribute that I added to each enum value, then creating a 'GetDescription' extension method on Enum. Then, whenever I flag an Error, its description gets writen out to the console/file/window or w/e.

I suppose I should have exposed some more of ILog's methods for this solution to have been found.

New FlagError Method:

public void
FlagError (Enum  errorCode)
{
   int  errorValue = Convert.ToInt32 (errorCode);

   if (errorValue == 0 || errorValue == int.MinValue
      || errorValue != (errorValue & -errorValue))
   {
      WriteError ("ErrorCode {0}: {1}",
                  errorValue,
                  errorCode.GetDescription ());

      m_errorCode = int.MinValue;

      throw new IndexOutOfRangeException ();
   }

   if ((m_errorCode & errorValue) == errorValue)
      return;

   WriteError ("ErrorCode {0}: {1}",
               errorValue,
               errorCode.GetDescription ());

   m_errorCode += errorValue;
}

GetDescription Extention Method:

public static string 
GetDescription (this Enum  @enum)
{
   StringBuilder  builder;

   var  descriptionAttributes = @enum.GetType ()
                                     .GetCustomAttributes (
                                          typeof (DescriptionAttribute),
                                          false) as DescriptionAttribute [];

   if (descriptionAttributes == null || descriptionAttributes.Length == 0)
      return string.Empty;

   builder = new StringBuilder ();

   foreach (DescriptionAttribute  description in descriptionAttributes)
   {
      builder.Append (description.Description);
      builder.AppendLine ();
   }

   return builder.ToString ();
}

Description Attribute:

public sealed class DescriptionAttribute : Attribute
{
   public 
   DescriptionAttribute (string  description)
   {
      m_description = description;
   }

   public string 
   Description
   {
      get
      {
          return m_description;
      }
   }


   private readonly string m_description;
}

If anyone has any additional input, I would love to hear it.

Meiscooldude
If you find you're using this extensively, a potential performance optimization would be to make the `DescriptionAttribute` class sealed, use an explicit backing string variable that's `readonly` and have the `Description` property have just a getter which accesses that explicit variable.
Jesse C. Slicer