Is there a way to use overridden behavior when calling the base class?

The title is a bit abstract, so it might be easier to explain with a concrete example:

I find it helpful to have my exception classes use the enum parameter instead of a string message.

throw new SpecificException(SpecificExceptionCode.ThisThingWentWrong);

      

There are several reasons for this, including:

  • I can code all the logic for accessing localized string resources in one place.
  • I can easily verify that I have string resources for all exception messages
  • Checking for correct exception messages in unit tests is easier

I would like to write a base class for this type of exception. Derived exception classes usually just want to provide their own System.Resources.ResourceManager, but can provide additional constructors as well. The problem comes from the fact that I can only call static methods when calling the base class constructors. This leads me to something like:

public abstract class BaseException : ApplicationException
{
    protected static ResourceManager m_resources;
    public BaseException(System.Enum errorCode, params object[] messageArgs) 
        : base(ProcessError(errorCode, messageArgs))
    {}

    private static string ProcessError(Enum errorCode, params object[] messageArgs)
    {
        string errorMessage = m_resources.GetString(errorCode.ToString());
        // Handling of messageArgs and trace logging
        // ....
        return finalError;
    }
}

      

and

public class SpecificException : BaseException
{
    static SpecificException()
    {
        m_resources = //.. Get an appropriate resource manager instance
    }

    public SpecificException(SpecificExceptionCode errorCode, params object[] messageArgs)
        : base(errorCode, messageArgs)
    {}
}

      

This works, but I am not happy that there is no compile time hint that the derived class should provide its own System.ResourceManager

. I would like to have a base class like:

public abstract class BaseException : ApplicationException
{
    protected abstract static ResourceManager Resources{get;}

    public BaseException(System.Enum errorCode, params object[] messageArgs) 
        : base(ProcessError(errorCode, messageArgs))
    {}

    private static string ProcessError(Enum errorCode, params object[] messageArgs)
    {
        string errorMessage = Resources.GetString(errorCode.ToString());
        // Handling of messageArgs and trace logging
        // ....
        return finalError;
    }
}

      

... but I can't have an abstract static method. Is there a better way?

+1


source to share


3 answers


Your current code doesn't work ... there is only one static field; the last static ctor to perform wins.

Re using a non-static method - note that calling virtual / abstract methods in the constructor is a little dangerous - the concrete class won't be initialized yet, so the override might try to use data that isn't available yet.

Can ResourceManager not be an argument to base-constructor? If they pass null, you use sensible defaults ... ProcessError will then accept a ResourceManager, etc.

public abstract class BaseException : ApplicationException
{
    static ResourceManager defaultManager;
    static ResourceManager DefaultManager
    {
        get
        {
            if (defaultManager == null) defaultManager = TODO; // sensible default
            return defaultManager;
        }
    }

    public BaseException(System.Enum errorCode, params object[] messageArgs)
        : this(DefaultManager, errorCode, messageArgs) {}
    public BaseException(ResourceManager resourceManager, System.Enum errorCode, params object[] messageArgs)
        : base(ProcessError(resourceManager, errorCode, messageArgs))
    { }

    private static string ProcessError(ResourceManager resourceManager, Enum errorCode, params object[] messageArgs)
    {
        if (resourceManager == null) throw new ArgumentNullException("resourceManager");
        string errorMessage = resourceManager.GetString(errorCode.ToString());
        // Handling of messageArgs and trace logging
        // ....
        return finalString;
    }
}

      



and

public class SpecificException : BaseException
{
    static ResourceManager customManager;
    static SpecificException()
    {
        customManager = //TODO - init manager
    }
    public SpecificException(SomeEnum errorCode, params object[] messageArgs)
        : base(customManager, errorCode, messageArgs)
    { }
}

      

Classes that don't want to provide their own manager just use a different ctor:

: base(errorCode, messageArgs)

      

+2


source


Why should it be a static property? You can create a normal Resources property:

protected abstract static ResourceManager Resources{get;}

      



and just leave it to implement to implement it to return a static object:

private static ResourceManager resources = ....

protected override static ResourceManager Resources{get {return resources; }}

      

0


source


Why not create a protected constructor that takes a resource manager as a parameter? So your specific exception would have to pass it.

I would use a factory method rather than a constructor for this kind of problem.

public static SpecificException SpecificExceptionCodeName()
{
    //Do resource lookup and create Exception
}

      

and then use

throw ExceptionBuilder.SpecificExceptionCodeName();

      

this way you get the benefits you drew without inheriting from a specific underlying Exception, which allows you to throw any Exception you like. There are several places within the framework where he uses this method internally. Note that I tend not to apply the factory method to a specific exception because they are mapped to derived classes that they can receive.

0


source







All Articles