使用 OOP 概念创建异常层






2.85/5 (8投票s)
本文介绍如何在应用程序中捕获异常。这个层有助于确定异常是从哪个层、模块和源发生的。
引言
撰写本文的目的是将概念付诸实践。在这里,我试图创建一个可插入且可重用的独立层。假设在应用程序中发生了一个异常。很难追踪异常来自哪个模块和层。捕获异常可能有最简单的方法,但我的目标是展示如何使代码片段可重用。
关键场景
使用
- 抽象类
- 接口
- 密封类
- 接口
异常层的实现
现在,让我们在实际应用程序中开始实现。创建一个 ExceptionAccessLayer.cs 文件,我们将在此定义各种类。
在类文件的 ExceptionAccessLayer
命名空间下,创建以下类和接口:
- 异常接口 (
IPALException
) Layer
类Module
类abstract class PALExceptionBase
:System.Exception
,IPALException
sealed class PALDataValidationException
:PALExceptionBase
sealed class PALSqlException
:PALExceptionBase
现在我们将逐一介绍这些类。
- Layer 类
在应用程序开发中,根据需求,我们总会有实现层,例如 DAL(数据访问层)、业务访问层、异常层、数据对象层、表示层等。简单来说,业务层包含所有业务模型的公式、计算或逻辑块。例如,利率计算等。如果我们谈论 DAL 层,我们实际上是在谈论加载组合框、打开连接、数据库调用等。下面是
Layer
类:#region Layer Class public class Layer { public const string BUSINESS = "01" ; public const string DATAOBJ = "02" ; public const string DALC = "03" ; } #endregion
- Module 类
在任何应用程序中,都有许多模块。一个模块可能有一个菜单,其中包含与其相关的各种进程。例如:
添加记录
显示记录
删除记录
修改记录
如果发生异常,则必须知道异常是从哪个模块引发的。因此,我们为此有一个容器类。
#region Module Class public class Module { public const string ADDRECORD = "01"; public const string DISPLAYRECORD = "02"; public const string DELETERECORD = "03"; public const string MODIFYRECORD = "04"; }#endregion
- 接口
一个
abstract
类可以有抽象成员和非抽象成员。但在接口中,所有成员都隐式是抽象的,并且接口的所有成员都必须由其派生类重写。接口的成员是public
的,没有实现。抽象类可以有protected
部分、static
方法等。一个类可以继承一个或多个接口,但只能继承一个抽象类。
#region Exception interface public interface IPALException { //Implemented into Class--All are Abstract--- string ErrDescription {get;set;} Exception InnerExceptionObj {get;set;} } #endregion
上述属性的实现(定义)将在下面的
abstract
类中完成。希望到目前为止我们思路一致。现在让我们看看其他部分。
- 抽象类
我们已经定义了一个抽象类,其方法处于非抽象状态。如果您想创建仅代表基类而不希望任何人创建这些类类型的对象的类,您可以使用抽象类使用 '
abstract
' 修饰符在 C# 中实现此类功能。这里的总体思路是声明和定义一个通用的异常基类,例如
PALException
(PAL:Project Access Layer)。现在我们可以有各种异常,它们可以是用户定义的,也可以是系统异常,并从中派生。在我们的例子中,
PALDataValidation
异常类将从PALException
基类派生,并使用PALException
基类的非抽象方法。抽象类
PALExceptionBase
继承System.Exception
和接口 'IPALException
'。让我们看看代码片段。
#region PALExceptionBase Class public abstract class PALExceptionBase : Exception , IPALException { private int _actualNumber ; private string _layer ; private string _module ; private string _description ; private Exception _innerException ; public PALExceptionBase(){} public PALExceptionBase(string layer, string module, string description, Exception innerException) { this._layer = layer ; this._module = module ; this._actualNumber = actualNumber ; this._description = description ; this._innerException = innerException ; } public string LayerType { get { return _layer; } set { _layer = value ;} } /// <summary> /// Gets ans Sets Module Type defined /// in Module Object of Fourseason Application /// </summary> public string ModuleType { get { return _module; } set {_module = value ; } } public string ErrDescription { get { return _description; } set { _description = value ; } } public Exception InnerExceptionObj { { get { return _innerException; } set { _innerException = value ; } } }
- 密封类
public sealed class PALDataValidationException : PALExceptionBase
现在看看我们上面声明的依赖项。该类是
sealed
的,因此它不能被派生或继承。这里有一个基本问题:我们为什么要这样做?您知道,有许多类型的异常。异常可以是用户定义的或系统定义的异常。在应用程序中,我们可能有SqlException.Math
异常、参数异常、内存异常等。我们可以在catch
块中抛出它们,但为了对它们进行分类,我们创建了PALDataValidationException
、PALSqlException
、PALMathException
等类。只需记住,当我们抛出异常时,我们将声明该类的对象并传递一个参数,例如EX(SqlException Ex)
、LayerName
、ModuleName
、ErrorDescription
。所以,让我们看看代码片段。
#region PALSqlException Class public sealed class PALSqlException: PALExceptionBase { public PALSqlException(){}//Default null constructor //Parametrized Constructor public PALSqlException (string layer, string module, int actualNumber,string description, Exception innerException): base(layer,module,description,innerException) {} } #endregion #region PALDataValidationException Class public sealed class PALDataValidationException : PALExceptionBase { public PALDataValidationException (){}//Default null constructor //Parametrized Constructor public PALDataValidationException (string layer, string module, int actualNumber,string description, Exception innerException): base(layer,module,description,innerException) {} }//....So on.. #endregion
看看我们如何使用
:base()
在实现类中使用抽象类。这就是为什么抽象类总是隐藏实现的。
希望到目前为止,我们在概念上有所理解,并在实际应用程序中获得了一些实现动力。
现在是出于学习目的故意抛出一些异常的时候了。
我尝试打开一个数据库。但是我们提供的连接字符串包含一些错误。我们故意没有提供密码。在我们的例子中,SQL Server 需要 Password=sa 才能打开连接。
try
{
SqlConnection objConn= new
SqlConnection("SERVER=localhost;Database=northwind;uid=sa;pwd=");
// See here we purposely not provided
// pwd though we require in our server
objConn.Open();
}
catch(SqlException ExERR)
{
PALSqlException objSQL=new PALSqlException(Layer.DALC,
Module.ADDRECORD,ExERR.Message,ExERR);
lbl2.Text=objSQL.LayerType;
lbl3.Text=objSQL.ModuleType;
lbl4.Text=objSQL.ErrDescription;
lbl5.Text=ExERR.Source;
}
看看在我们的例子中,我们创建了一个 PALSqlException
对象。同样,我们可以从抽象基类 PALException
创建许多类(PALDataValidationexception
、PALSqlEXception
、PALFileException
: PALException
)。
PALSqlException objSQL=
new PALSqlException(Layer.DALC, Module.ADDRECORD,
ExERR.Message, ExERR);
输出
- 层:03
- 模块:01
- 错误描述:用户 'sa' 登录失败。
- 异常:.NET SqlClient 数据提供程序
其他文章
结论
任何建议、批评或信息都非常欢迎。