1

我是 OOP 的新手,所以我需要帮助来了解这是否是处理它的正确方法。我有一个 3 层 Web 项目(+ DTO),我试图了解这是从业务对象返回“错误”到表示层的最佳方式。特别是现在我正面临这个创建用户的问题。假设我想在网站注册时在数据库中创建用户,我需要告诉实际用户用户名或电子邮件是否已经被使用(这只是一个例子)。

例如,ASP.NET Membership.CreateUser() 方法通过引用传递一个 MembershipCreateStatus 对象,因此该方法用于返回一个 Enum(位于另一个命名空间中......)以传递尝试的状态,这可能是 DuplicateEmail,重复用户名,等等。

我根据异常实现了另一种方式,但我想听听你的意见。在创建用户的 BLL 管理器类中,我以这种方式创建了一个嵌套的 Excpetion 类和嵌套的 Enums 错误类型:

Public Class UserManager
    Public Enum ErrorType
        DatabaseError = 1
        UserExists = 2
        EmailExists = 3
    End Enum

    Public Class ManagerException
        Inherits Exception

        Public Property ErrorType As ErrorType
        Public Property SuggestedUserName As String
        Public Property SuggestedEmail As String

        Public Sub New()
            MyBase.New()
        End Sub

        Public Sub New(message As String)
            MyBase.New(message)
        End Sub

        Public Sub New(message As String, inner As Exception)
            MyBase.New(message, inner)
        End Sub
    End Class


    Public Function CreateUserLogin(user As EvaVwUserLogin) As Guid
        If user Is Nothing Then
            Throw New ApplicationException("No user suppied")
        End If

        If String.IsNullOrWhiteSpace(user.Password) OrElse String.IsNullOrWhiteSpace(user.UserName) Then
            Throw New ApplicationException("Password or username missing")
        End If

        If CheckDuplicateUserName() Then
            Dim ex As New ManagerException("Username exists")

            ex.ErrorType = ErrorType.UserExists
            ex.SuggestedUserName = "this username is free"

            Throw ex
        End If
    End Function
End Class

然后在 UI 层(后面的 aspx 代码)我调用管理器并检查异常,如下所示:

        Dim userManager As New UserManager

        Try
            userManager.CreateUserLogin("test", "test")
        Catch ex As UserManager.ManagerException
            If ex.ErrorType = userManager.ErrorType.UserExists Then
                Dim suggestedUsername = ex.SuggestedUserName

                ' Display error message and suggested user name
            End If
        End Try

这是一个正确的方法吗,考虑到异常和枚举都非常特定于这个经理,所以如果我沿着这条路走,每个经理都会有嵌套的 ManagerException 和相关的枚举?

一如既往地提前感谢您的意见。


跟进 Brian 和 Cyborg 建议的“自定义代码”场景(我标记了他的答案只是因为它更完整,Brian 也许其他用户对 MS 建议感兴趣)你认为在管理器类中嵌套自定义返回对象和相关枚举会是个好主意吗?由于这些枚举将与这个管理器类严格相关(并且 BLL 中的每个 managar 类都有自己的)你认为我仍然可以将它们用作传递的状态码吗?

编辑:我以这种方式重构......你认为它可以吗?

Public Class UserManager
    Public Enum ErrorType
        DatabaseError = 1
        UserExists = 2
        EmailExists = 3
    End Enum

    Public Class ErrorData
        Public Property ErrorType As ErrorType
        Public Property SuggestedUserName As String
        Public Property SuggestedEmail As String
    End Class

    Public Function CreateUserLogin(username As String, password As String, ByRef errorData As ErrorData) As Guid
        Dim user As New EvaVwUserLogin

        user.UserName = username
        user.Password = password

        Return CreateUserLogin(user, errorData)
    End Function

    Public Function CreateUserLogin(user As EvaVwUserLogin, ByRef errorData As ErrorData) As Guid
        If user Is Nothing Then
            Throw New ApplicationException("No user object")
        End If

        If String.IsNullOrWhiteSpace(user.Password) OrElse String.IsNullOrWhiteSpace(user.UserName) Then
            Throw New ApplicationException("Missing password or username")
        End If

        Dim hashedPassword As String

        hashedPassword = Crypto.HashPassword(user.Password)

        If UserExists(user) Then
            errorData.ErrorType = ErrorType.UserExists
            errorData.SuggestedUserName = "this username is free"
            Return Nothing
        End If
        .....
    End Function
End Class

在表示层:

        Dim userManager As New UserManager
        Dim managerError As New UserManager.ErrorData
        Dim userId As Guid

        userId = userManager.CreateUserLogin("test", "test", managerError)

        If userId = Nothing Then
            If managerError.ErrorType = userManager.ErrorType.UserExists Then
                Dim suggestedUserName = managerError.SuggestedUserName

                ' Do something with suggested user name
            End If
        End If
4

2 回答 2

2

为此,我将遵循 Membership API 的功能。从您的业务组件返回一个枚举,视图可以使用它来检查响应。因此,您返回一个带有您提到的值的枚举到 ASP.NET 页面,并检查那里的类型。你可以做你正在做的事情,但据我所知,我认为没有必要;另外,抛出异常是昂贵的。

为了澄清我的意思是枚举是从业务组件的调用者返回它,而不是通过异常。

于 2013-01-14T20:45:58.930 回答
1

(这个答案只是为了支持@BrianMains 建议使用返回码而不是异常。相关文档太大而无法放入评论中。)

从关于异常的 MSDN 文档:

抛出或处理异常时会占用大量系统资源和执行时间。抛出异常仅用于处理真正异常的情况,而不是处理可预测的事件或流控制。例如,如果方法参数无效,您的应用程序可以合理地抛出异常,因为您希望使用有效参数调用您的方法。无效的方法参数意味着发生了异常情况。相反,如果用户输入无效,请不要抛出异常,因为您可以预期用户偶尔会输入无效数据。在这种情况下,提供重试机制,以便用户可以输入有效输入。

仅在特殊情况下抛出异常,然后在适用于大多数应用程序的通用异常处理程序中捕获异常,而不是在适用于特定异常的处理程序中捕获异常。这种方法的基本原理是大多数错误都可以通过靠近错误的验证和错误处理代码来处理。不需要抛出或捕获异常。通用异常处理程序捕获应用程序中任何地方抛出的真正意外的异常。

另外,当返回码足够时不要抛出异常;不要将返回码转换为异常;并且不要例行捕获异常,忽略它,然后继续处理。

http://msdn.microsoft.com/en-us/library/system.exception.aspx

(突出我的)

于 2013-01-14T20:56:08.870 回答