标题有点抽象,所以可能更容易用一个具体的例子来解释:
我发现让异常类采用枚举参数而不是字符串消息很有用。
throw new SpecificException(SpecificExceptionCode.ThisThingWentWrong);
这样做的原因很少,包括:
我想为这种类型的异常编写一个基类。派生的异常类通常只想提供自己的System.Resources.ResourceManager,但也可能提供其他构造函数。麻烦来了,因为我只能在调用基类构造函数时调用静态方法。这导致我有类似的事情:
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;
}
}
和
public class SpecificException : BaseException
{
static SpecificException()
{
m_resources = //.. Get an appropriate resource manager instance
}
public SpecificException(SpecificExceptionCode errorCode, params object[] messageArgs)
: base(errorCode, messageArgs)
{}
}
这很有效,但我对它不满意,因为没有编译时暗示派生类必须提供自己的System.ResourceManager
。我想有一个基类,如:
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;
}
}
...但我不能有一个抽象的静态方法。还有更好的方法吗?
答案 0 :(得分:2)
您当前的代码已损坏...只有一个静态字段;执行胜利的最后一个静态ctor。
重新使用非静态方法 - 请注意,在构造函数中调用虚拟/抽象方法有点危险 - 具体类尚未初始化,因此覆盖可能会尝试使用尚不可用的数据
ResourceManager不能是基础构造函数的参数吗?如果它们传递null,则使用合理的默认值... 然后ProcessError将接受ResourceManager等
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;
}
}
和
public class SpecificException : BaseException
{
static ResourceManager customManager;
static SpecificException()
{
customManager = //TODO - init manager
}
public SpecificException(SomeEnum errorCode, params object[] messageArgs)
: base(customManager, errorCode, messageArgs)
{ }
}
不想提供自己的经理的类只使用另一个ctor:
: base(errorCode, messageArgs)
答案 1 :(得分:0)
为什么它必须是静态属性?您可以使资源正常属性:
protected abstract static ResourceManager Resources{get;}
然后让实现者实现它以返回一个静态对象:
private static ResourceManager resources = ....
protected override static ResourceManager Resources{get {return resources; }}
答案 2 :(得分:0)
为什么不使用受资源管理器作为参数的受保护构造函数?这样你的具体例外就必须传入它。
我倾向于使用工厂方法而不是构造函数来解决这类问题。
public static SpecificException SpecificExceptionCodeName()
{
//Do resource lookup and create Exception
}
然后使用
throw ExceptionBuilder.SpecificExceptionCodeName();
通过这种方式,您可以获得所概述的好处,而无需继承特定的基本异常,从而允许您抛出任何您喜欢的异常。框架中有几个地方在内部使用此方法。请注意,我倾向于不将工厂方法放在具体的异常上,因为它们会出现在可以得到的派生类上。