2011-03-22 65 views
5

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

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

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

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

回答

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 

编辑

您可能需要根据您的目标是如何设置上GetProperties()BindingFlags玩。

EDIT 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

感谢克里斯哈斯的关键字,我能够进一步研究这个话题。我发现another answer不使用Of T As New,我最终使用它,因为我的DTO不声明任何构造函数。

根据记录,这是我最后使用:

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 

下面是使用上述功能的客户端:

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