65.9K
CodeProject 正在变化。 阅读更多。
Home

业务对象属性验证

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.43/5 (9投票s)

2006年11月9日

CPOL

5分钟阅读

viewsIcon

45146

downloadIcon

254

如何在一行代码中设置和验证属性。

Sample Image - bizobjpropertyvalidation.jpg

引言

大家好。我目前正在开发一个内部使用的n层应用程序,并通过反射减少了大量的代码。唯一仍然需要手动、繁琐编码的部分是客户端业务对象。对于较小的对象,这不算什么大问题,但其中一些对象有100多个公共读/写属性——当然,还有存储数据的私有字段声明。我真正反对的是构建属性和包含一些基本的验证和错误检查的重复性工作。

使用代码

为了方便阅读,示例已经简化,但可以根据您的需求进行扩展并移至不同的层。我包含了一个BusinessRules程序集,其中包含许多自定义属性。这些属性进一步简化了验证过程,但属性是另一篇文章的主题。

属性 - Structures.vb

我们将从一个structTEST结构开始。它将作为业务对象的变量和属性,并将被验证。

Option Strict Off
Option Explicit On

Imports BusinessRules.Attributes

Namespace Structures

    Public Structure structTEST
    
        'Use the custom attributes defined in the BusinessRules.Attributes 
        'namespace. These attributes will form part of the general/generic
        'business rules that apply to this property
        <NotNull(), NotEmpty(), MaxLength(50)> Public Name As String
        
    End Structure
        
End Namespace

注意:我总是将我的结构放在Structures命名空间中,以保持应用程序的有序和逻辑。这些结构通常保存在服务器端业务对象和/或DAL接口声明的同一个模块中。它们可以放在一个Structures项目,或者全部存储在一个Structure代码模块中。选择权在于您。

验证器 - CProps.vb

这个类做了所有工作……它将执行属性的Get/Set,执行验证,并抛出任何错误/异常。

Option Strict Off
Option Explicit On 

Imports PropsVal.Structures

Imports BusinessRules.Attributes
Imports BusinessRules.Errors

Imports System.Reflection

在这里,我们设置了强制性内容并导入了相应的命名空间。请注意,我们导入了BusinessRules.AttributesBusinessRules.Errors命名空间以及System.Reflection

Public Class CProps

#Region " Private Attributes "

    Private mVTProps As ValueType
    Private lType As Type

#End Region

现在,我们定义类名并开始声明一些模块变量。请注意,mVTProps对象被声明为ValueType

#Region " Private Properties "

    Private ReadOnly Property VTType() As Type
        Get
            Try

                If lType Is Nothing Then
                    lType = mVTProps.GetType
                End If

                Return lType

            Catch ex As Exception

                Throw ex

            End Try
        End Get
    End Property

#End Region

现在,我们定义一个稍后将使用的私有属性。此属性的作用是向内部方法返回一个System.Type,因为它们需要它(如下所示)。

#Region " Constructors "

    Public Sub New(ByVal typeName As String)

        Try

            Dim t As Type = Type.GetType(typeName)

            If t Is Nothing Then
                Throw New Exception("Type could not be loaded.")
                Return
            End If

            mVTProps = Activator.CreateInstance(t)

        Catch ex As Exception

            Throw ex

        End Try

    End Sub

#End Region

继续……定义了构造函数。在这里,我们使用typeNameString)参数来初始化模块变量(上面)。

#Region " Public Methods "

    Public Sub SetValue(ByVal propName As String, ByVal val As Object)

        Try

            Dim lObjFI As FieldInfo = VTType.GetField(propName)

            lObjFI.SetValue(mVTProps, val)

            BusinessRules.Validate.Validation.ValidateAndThrow(mVTProps, propName)

        Catch ex As Exception

            Throw ex

        End Try

    End Sub

然后,进入工作人员。与所有读/写属性一样,都有一个Set块。这是Set块。现在,还记得上面我们将mVTProps变量声明为ValueType吗?这是因为结构是值类型。FieldInfo.SetValue只能作用于Object类型(任何熟悉此问题的人都可以随意阐述)。

    Public Function GetValue(ByVal propName As String)

        Try

            Dim lObjFI As FieldInfo = VTType.GetField(propName)

            Return lObjFI.GetValue(mVTProps)

        Catch ex As Exception

            Throw ex

        End Try

    End Function

    Public Function GetAllData() As ValueType

        Return mVTProps

    End Function

#End Region

End Class

……这是Get块和类的结尾。

业务对象

业务对象是用户界面将与之通信的对象。

Option Strict Off
Option Explicit On 

Imports PropsVal.Structures

Imports System.Reflection

Public Class BizO

#Region " Public Properties "

    Public PROPS As CProps

#End Region

再次,我们设置选项并导入命名空间;定义类和公共属性。PROPS声明是您通常声明所有变量(string、int、GUID等)的地方,然后您将拥有所有属性声明以及任何/所有验证和错误检查代码。

#Region " Constructors "

    Public Sub New()

        'Initialise the PROPS object
        PROPS = New CProps(GetType(Structures.structTEST).FullName)

    End Sub

#End Region

#Region " Public Methods "

    Public Sub Load()

        'This is where you would make calls to your database, 
        'DAL, or remote objects. This would return the data 
        'and fill the PROPS object (above)

        'This model can then be expanded upon by providing similar
        'method - ie Save, Rollback, etc...

    End Sub

#End Region

End Class

构造函数是初始化PROPS对象的地方。这是此解决方案的关键要素,因为类型必须正确,但即使这样也不算太难。还记得我们之前创建的结构吗?这就是我们实际使用它的地方。使这一切生效的关键是解析结构的Type FullName

在这里,我特意将Load方法留空,但根据代码注释,您可以看到可以做什么。

UI - form1.vb

是的,是的。我知道名字很随意。您需要添加的唯一代码是关于按钮的代码。

'Declare and instantiate the BizO business object
Dim o As BizO
o = New BizO

Try
    'Set the value of the Name property in the business object
    o.PROPS.SetValue("Name", txtName.Text)

    'No exceptions/errors were detected during the value set
    'so report the success to the user
    lblErrMsg.Text = "Input tested successfully!!"
    pnlStatus.BackColor = Color.Green

Catch ex As Exception
    'An exception was thrown from within the PROPS object (inside
    'the business object
    'Report the error message to the user
    lblErrMsg.Text = ex.Message
    pnlStatus.BackColor = Color.Red
End Try

'Display the results to the user
lblResult.Text = "PROPS.GetValue: " + o.PROPS.GetValue("Name")

'Declare a local instance of structTEST structure
Dim x As Structures.structTEST
'and fill it with ALL the data from the PROPS object
x = o.PROPS.GetAllData

'Display the results to the user
lblResult.Text += vbCrLf + vbCrLf + "Local structure: " + x.Name

好的,最后一部分……在这里,我们声明并实例化一个新的业务对象。

然后,我们尝试将Name属性设置为文本框Text属性的值。如果没有错误/异常,我们将显示成功消息并将面板设置为绿色。任何异常都会导致显示错误消息并将面板更改为红色。

然后,纯粹是为了测试目的,在我构建此内容时,我们检索Name属性的值并将其显示在屏幕上,最后我们声明structTEST结构的新实例并用PROPS对象的内容/值填充它,并显示Name成员的值。

关注点

  • 上述代码最初在v1.1框架上开发的。由于我还没有使用v2.0,我只能假设上述内容会起作用,但请不要引用我的话。在将其移植到VS2005(Framework 2.0)解决方案然后是VS2008之后,没有出现任何问题,并且该模型正在使用中,而且每天都在被更多地使用。
  • structTEST结构是值类型,使用FieldInfo.SetValue只能作用于对象类型。幸运的是,结构很容易转换为值类型对象。
  • Option Strict设置为Off,仅仅是因为将结构转换为ValueType对象而不进行CType会失败,而且我发现当严格类型设置为开启时,有太多其他隐式类型转换会失败。
  • GetAllData方法可用于将内容/值解析到数据库、DAL、或远程对象,因为返回的对象是structTEST结构。我正在开发的应用程序将这些结构解析到一个可远程化的业务对象(通过接口),在那里进行最终的检查和验证。然后,结构被解析到DAL,其中结构用于填充存储过程参数(使用成员名称和进一步的自定义属性),并将其解析到SQL数据库。
  • 我本想利用IntelliSense来获取属性名称,而不是使用String字面量,但我担心这会增加额外的开销,从而抵消任何性能和/或简洁性。有什么想法吗?
  • 我确信还有很多可以做得更好的地方,我非常乐意听到您的意见。毕竟,我们都在这里学习。

结论

如今,每个人都必须在更少的帮助下做更多的事情,而且这总是在昨天就该完成。希望这个例子能帮助您减少乏味的工作,让您能继续做真正酷的事情。如果我再次受到启发,我可能会提交一些关于我发现、创建和使用的各种技术以节省时间和代码的进一步文章。

© . All rights reserved.