定义自己的异常类
- 设计自己的异常不仅繁琐,还容易出错。主要原因是从Exception派生的所有类型都应该是可序列化的(serializable),使它们能穿越AppDomain边界或者写入日志/数据库。
写一个自己的泛型Exception<TExceptionArgs>
类,它像下面这样定义
[Serializable]
public sealed class Exception<TExceptionArgs> : Exception, ISerializable
where TExceptionArgs : ExceptionArgs
{
private const String c_args = "Args"; // For (de)serialization
private readonly TExceptionArgs m_args;
public TExceptionArgs Args
{
get
{
return m_args;
}
}
public Exception(String message = null, Exception innerException = null)
: this(null, message, innerException) { }
public Exception(TExceptionArgs args, String message = null,
Exception innerException = null): base(message, innerException)
{
m_args = args;
}
// This constructor is for deserialization; since the class is sealed, the constructor is
// private. If this class were not sealed, this constructor should be protected
[SecurityPermission(SecurityAction.LinkDemand,
Flags = SecurityPermissionFlag.SerializationFormatter)]
private Exception(SerializationInfo info, StreamingContext context)
: base(info, context)
{
m_args = (TExceptionArgs)info.GetValue(c_args, typeof(TExceptionArgs));
}
// This method is for serialization; it’s public because of the ISerializable interface
[SecurityPermission(SecurityAction.LinkDemand,
Flags = SecurityPermissionFlag.SerializationFormatter)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue(c_args, m_args);
base.GetObjectData(info, context);
}
public override String Message
{
get
{
String baseMsg = base.Message;
return (m_args == null) ? baseMsg : baseMsg + " (" + m_args.Message + ")";
}
}
public override Boolean Equals(Object obj)
{
Exception<TExceptionArgs> other = obj as Exception<TExceptionArgs>;
if (other == null) return false;
return Object.Equals(m_args, other.m_args) && base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
TExceptionArgs约束为的ExceptionArgs基类非常简单,它看起来像下面这样
[Serializable]
public abstract class ExceptionArgs {
public virtual String Message { get { return String.Empty; } }
}
要定义代表磁盘满的异常类,可以像下面这样
[Serializable]
public sealed class DiskFullExceptionArgs : ExceptionArgs {
private readonly String m_diskpath; // private field set at construction time
public DiskFullExceptionArgs(String diskpath) { m_diskpath = diskpath; }
// Public readonly property that returns the field
public String DiskPath { get { return m_diskpath; } }
// Override the Message property to include our field (if set)
public override String Message {
get {
return (m_diskpath == null) ? base.Message : "DiskPath=" + m_diskpath;
}
}
}
现在,可以像下面这样写来抛出并捕捉这样的一个异常
public static void TestException() {
try {
throw new Exception<DiskFullExceptionArgs>(
new DiskFullExceptionArgs(@"C:\"), "The disk is full");
}
catch (Exception<DiskFullExceptionArgs> e) {
Console.WriteLine(e.Message);
}
}