函数返回参数中指定类型的对象

时间:2011-03-22 05:04:34

标签: vb.net

如何创建一个返回特定类型对象的函数,该函数的用户在参数中指定(使用vb.net 2010)?

Private Function TryThis(ByVal t As Type) As Object
    Dim n = New t
    Return n
End Function

上面的代码不起作用,但也许它可以解释我想要实现的目标。

使用此功能,我想从数据表中保存数据传输对象。客户端只需调用此函数,指定客户端需要哪个DTO,此函数将创建该DTO并使用反射GetType.GetProperties()填充属性。

2 个答案:

答案 0 :(得分:4)

这是一个使用泛型的非常基本的例子。方法GetPropFromDatabase只使用Select Case,但您显然会进行真正的数据库查找调用。

Option Explicit On
Option Strict On

Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim X = CreateObject(Of TestClass)()

        Trace.WriteLine(X.PropertyA)
        Trace.WriteLine(X.PropertyB)

        Me.Close()
    End Sub

    ''//Of T as New means that the object must have a constructor
    Private Function CreateObject(Of T As New)() As T
        ''//Create our object
        Dim O As New T
        ''//Get the type properties
        Dim Props = GetType(T).GetProperties()
        ''//Loop through each property
        For Each P In Props
            ''//Set the value of our return type by property name
            P.SetValue(O, GetPropFromDatabase(P.Name), Nothing)
        Next
        ''//Return our object
        Return O
    End Function
    ''//This function would obviously do a lot more
    Private Shared Function GetPropFromDatabase(ByVal name As String) As String
        Select Case name
            Case "PropertyA"
                Return "Value1"
            Case "PropertyB"
                Return "Value2"
        End Select

        Throw New ApplicationException(String.Format("Unknown database column : {0}", name))
    End Function
End Class
Public Class TestClass
    Public Property PropertyA As String
    Public Property PropertyB As String
End Class

修改

您可能需要在BindingFlags上使用GetProperties(),具体取决于对象的设置方式。

编辑2

您可能还想查看使用自定义属性。例如,如果您的数据库中有一个名为[First Name]的列,由于空间的原因,它显然不能作为对象属性存在。使用自定义属性,您可以标记某些属性,以便以特殊方式忽略或解析。下面的代码显示了上述代码的扩展版本。

Option Explicit On
Option Strict On

Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim X = CreateObject(Of TestClass)()

        Trace.WriteLine(X.PropertyA)
        Trace.WriteLine(X.PropertyB)
        Trace.WriteLine(X.FirstName)

        Me.Close()
    End Sub

    ''//Of T as New means that the object must have a constructor
    Private Function CreateObject(Of T As New)() As T
        ''//Create our object
        Dim O As New T
        ''//Get the type properties
        Dim Props = GetType(T).GetProperties()

        ''//Will hold the name of the database column to get the value of
        Dim PropName As String
        ''//Will hold our collection of attributes on the property
        Dim CustomAttributes() As Object
        ''//Loop through each property
        For Each P In Props
            ''//Default the value to the property name
            PropName = P.Name
            ''//Try to get any custom attributes for the property
            CustomAttributes = P.GetCustomAttributes(True)
            ''//See if we have anything to work with
            If (CustomAttributes IsNot Nothing) AndAlso (CustomAttributes.Count > 0) Then
                ''//Loop through each attribute
                For Each A In CustomAttributes
                    ''//If the attribute is our custom one defined below
                    If TypeOf A Is ColumnNameInDatabase Then
                        ''//Use the manually set column name instead
                        PropName = DirectCast(A, ColumnNameInDatabase).ColumnNameInDatabase
                        ''//No reason to loop through any more attributes so exit
                        Exit For
                    End If
                Next
            End If
            ''//Set the value of our return type by property name
            P.SetValue(O, GetPropFromDatabase(PropName), Nothing)
        Next
        ''//Return our object
        Return O
    End Function
    ''//This function would obviously do a lot more
    Private Shared Function GetPropFromDatabase(ByVal name As String) As String
        Select Case name
            Case "PropertyA"
                Return "Value1"
            Case "PropertyB"
                Return "Value2"
            Case "First Name"
                Return "Bob Dole"
        End Select

        Throw New ApplicationException(String.Format("Unknown database column : {0}", name))
    End Function
End Class
Public Class TestClass
    Public Property PropertyA As String
    Public Property PropertyB As String
    <ColumnNameInDatabase("First Name")> Public Property FirstName As String
End Class
Public Class ColumnNameInDatabase
    Inherits Attribute
    Private _ColumnNameInDatabase As String
    Public ReadOnly Property ColumnNameInDatabase As String
        Get
            Return Me._ColumnNameInDatabase
        End Get
    End Property
    Public Sub New(ByVal columnNameInDatabase As String)
        Me._ColumnNameInDatabase = columnNameInDatabase
    End Sub
End Class

答案 1 :(得分:1)

感谢Chris Haas的关键词,我能够进一步研究这个话题。我发现another answer不使用Of T As New,我最终使用Private Function DataRowToObject(Of T)(ByVal source As DataRow) As T Dim destination = GetType(T).GetConstructor(System.Type.EmptyTypes).Invoke({}) Dim props = destination.GetType.GetProperties() Dim propnames = props.Select(Function(x) x.Name.ToLower) For Each col In source.Table.Columns Dim colname = col.ColumnName.ToLower() If propnames.Contains(colname) Then Dim prop = props.Where(Function(x) x.Name.ToLower = colname).First If IsDBNull(source(col)) And prop.PropertyType Is GetType(String) Then prop.SetValue(destination, "", Nothing) ElseIf IsDBNull(source(col)) Then prop.SetValue(destination, Nothing, Nothing) Else prop.SetValue(destination, source(col), Nothing) End If End If Next Return destination End Function Protected Function DataTableToList(Of T)(ByVal source As DataTable) As IList(Of T) Dim destination As New List(Of T) For Each row In source.Rows Dim obj = DataRowToObject(Of T)(row) destination.Add(obj) Next Return destination End Function 因为我的DTO没有声明任何构造函数。

记录中,这是我最终使用的内容:

Public Function PeopleAll() As IList(Of DTO.People)
    Dim ResultTbl As New DataTable
    adp.TableLoad("select * from people", ResultTbl)

    Dim result = DataTableToList(Of DTO.People)(ResultTbl)
    Return result
End Function

这是一个使用上述功能的客户端:

Public Class People
    Public Overridable Property ID As Int64
    Public Overridable Property Name As String
    Public Overridable Property Email As String
End Class

以下是我的数据传输对象示例:

{{1}}