VB.NET - 从函数

时间:2017-10-16 16:44:40

标签: vb.net list class

我遇到的问题在以下代码中。该函数适用于ControlCaption实体类,但我必须为我需要读取的每个其他实体类复制并粘贴它,然后将ControlCaption更改为新的类名(我不喜欢在我不知道时重复代码)不得不)。因为还有一个更新/插入值的函数,我试图将公共对象设置为等于类(即Public SomeClass as Object = New ControlCaption),但是IDE抱怨它。

以下是代码:

Public Function SelectList(Optional ByVal SQLString As String = "SELECT * FROM " & DatabaseName) As List(Of ControlCaption)
    Dim strConnectionString As String = ConnectionString()      '--Creates the connection string
    Dim intLineNumber As Integer = 0
    Dim InfoList As New List(Of ControlCaption) '--List of classes being returned

    Try
        If DatabaseType = SQLServer Then    '--User indicated previously that a SQL Server was being used
            Using myConnection As New SqlClient.SqlConnection(strConnectionString)
                myConnection.Open()
                Using myCommand As New SqlClient.SqlCommand(SQLString, myConnection)
                    Using myReader = myCommand.ExecuteReader
                        Do While myReader.Read
                            InfoList.Add(New ControlCaption()) '--Add a new element to the list

                            '--The next couple of lines need System.Reflection to be imported to work
                            '--The following for statement goes through each property in a class and assigns
                            '--the database value with the same name to the property. (Required to use entity classes)
                            Dim TheObject As New ControlCaption
                            Dim TheType As Type = TheObject.GetType()
                            Dim Properties() As PropertyInfo = TheType.GetProperties()
                            For Each Prop As PropertyInfo In properties
                                Try
                                    If UCase(Prop.Name) <> "ITEM" Then
                                        If TypeOf (myReader.Item(Prop.Name)) Is DateTime Then
                                            '--Convert value to date
                                            InfoList(InfoList.Count - 1).Item(Prop.Name) = CDate(IIf((myReader.Item(Prop.Name).ToString & String.Empty) = vbNullString, "1/1/1900", myReader.Item(Prop.Name).ToString))
                                        Else
                                            InfoList(InfoList.Count - 1).Item(Prop.Name) = myReader.Item(Prop.Name).ToString & String.Empty
                                        End If
                                    End If
                                Catch ex As Exception

                                End Try
                            Next
                        Loop
                    End Using
                End Using

                If myConnection.State <> ConnectionState.Closed Then
                    myConnection.Close()
                End If

                Return InfoList
            End Using
        ElseIf DatabaseType = AccessDatabase Then
            Using myConnection As New OleDb.OleDbConnection(strConnectionString)
                myConnection.Open()
                Using myCommand As New OleDb.OleDbCommand(SQLString, myConnection)
                    Using myReader = myCommand.ExecuteReader
                        Do While myReader.Read
                            InfoList.Add(New ControlCaption())

                            Dim TheObject As New ControlCaption
                            Dim TheType As Type = TheObject.GetType()
                            Dim Properties() As PropertyInfo = TheType.GetProperties()
                            For Each Prop As PropertyInfo In properties
                                Try
                                    If UCase(Prop.Name) <> "ITEM" Then
                                        If TypeOf (myReader.Item(Prop.Name)) Is DateTime Then
                                            InfoList(InfoList.Count - 1).Item(Prop.Name) = CDate(IIf((myReader.Item(Prop.Name).ToString & String.Empty) = vbNullString, "1/1/1900", myReader.Item("DateModified").ToString))
                                        Else
                                            InfoList(InfoList.Count - 1).Item(Prop.Name) = myReader.Item(Prop.Name).ToString & String.Empty
                                        End If
                                    End If
                                Catch ex As Exception

                                End Try
                            Next
                        Loop
                    End Using
                End Using

                If myConnection.State <> ConnectionState.Closed Then
                    myConnection.Close()
                End If

                Return InfoList
            End Using
        Else
            Return Nothing
        End If
    Catch ex As Exception
        Return Nothing
    End Try
End Function

我觉得有必要让这个功能接受任何课程,但我还没有想出办法。

有没有人对如何使这项工作有任何建议?任何改进建议也会有所帮助。

谢谢。

对于任何有兴趣的人,这是最终生成的代码:

Public Function SelectList(Of EntityClass As New)(Optional ByVal SQLString As String = "SELECT * FROM " & DatabaseName) As List(Of EntityClass)
    Try
        Dim Entities As New List(Of EntityClass)()
        Using Connection As New SqlClient.SqlConnection(ConnectionString)
            Using Command As New SqlClient.SqlCommand(SQLString, Connection)
                Connection.Open()
                Using Reader = Command.ExecuteReader()
                    Dim Properties = GetType(EntityClass).GetProperties()
                    Do While Reader.Read
                        Dim Entity = CreateEntity(Of EntityClass)(Reader, Properties)
                        Entities.Add(Entity)
                    Loop
                End Using
            End Using
        End Using

        Return Entities
    Catch ex As Exception
        MsgBox(Err.Description)
        Return Nothing
    End Try
End Function

Private Function CreateEntity(Of PassedEntity As New)(ByVal reader As DbDataReader, ByVal properties As PropertyInfo()) As PassedEntity
    Dim Entity As New PassedEntity()
    For Each _Property As PropertyInfo In properties
        If _Property.Name.ToUpper() = "ITEM" Then Continue For

        Dim value = reader.Item(_Property.Name)
        _Property.SetValue(Entity, value, Nothing)
    Next
End Function

3 个答案:

答案 0 :(得分:1)

看起来像是#34; New&#34;限制。
&#34;新&#34;约束将提供创建给定类型的新实例的可能性。

Public Function SelectList(Of T As New)(query As String ) As List(Of T)
    Dim list As New List(Of T)()

    ' Somewhere in the rows loop
        Dim item = New T()
        ' Fill properties
        list.Add(item)

    Return list 
End Function

如果您讨厌重复的代码,那么您可以使用DbDataReader类删除一些重复,这是SqlDataReaderOleDbDataReader的基类。

Private Function CreateEntity<(Of T As New)(reader As DbDataReader, 
                                            properties As PropertyInfo()) As T
    Dim entity As New T()
    For Each property As PropertyInfo In properties
        If property.Name.ToUpper() = "ITEM" Then Continue For

        Dim value = reader.Item(property.Name)
        ' Should work if property type is correspondent .NET type of sql column type
        ' For null values property should be of Nullable type
        property.SetValue(entity, value)
        ' If not - use your logic
    Next       
End Function

在阅读逻辑中使用此功能。请注意,您不需要在每个循环中运行Type.GetProperties() - 为类型获取一次并重新生成相同的集合

Public Function SelectList(Of T As New)(query As String ) As List(Of T)
    Dim entities As New List(Of T)()

    Using connection As New SqlConnection(connectionString)
        Using command As new SqlCommand(query, connection)
            connection.Open()
            Using reader = command.ExecuteReader()
                Dim properties = GetType(T).GetProperties()
                Do While reader.Read()
                    Dim entity = CreateEntity(reader, properties)
                    list.Add(entity)
                Loop
            End Using
        ' No need for closing connection explicitly - End Using - will handle it
        End Using
    End Using

    Return entities 
End Function

答案 1 :(得分:0)

只需将函数参数设置为Object类型,然后可以将其传递给任何对象类型。例如:

    Public Function SelectList(Optional ByVal SQLString As String = "SELECT * FROM " & DatabaseName) As List(Of Object)

答案 2 :(得分:0)

使其成为通用的。只需返回可以实例化的对象列表。

它将被称为:

Dim myFoo As List(Of Foo) = SelectList(Of Foo)("Select * FROM Foo")

这是新代码

Public Function SelectList(Of T As New)(Optional ByVal SQLString As String = "SELECT * FROM " & DatabaseName) As List(Of T)
    Dim InfoList As New List(Of T) '--List of classes being returned
    Dim connectionType = If(DatabaseType = SQLServer, connectionType.MsSql, connectionType.MsAccess)
    Try
        Using myConnection = getConnection(connectionType, ConnectionString())
            myConnection.Open()
            Using myCommand = getCommand(connectionType, SQLString, myConnection)
                Using myReader = myCommand.ExecuteReader
                    Do While myReader.Read
                        Dim TheObject As New T()
                        InfoList.Add(TheObject) '--Add a new element to the list
                        Dim TheType As Type = TheObject.GetType()
                        Dim Properties() As PropertyInfo = TheType.GetProperties()
                        For Each Prop As PropertyInfo In Properties
                            Try
                                If UCase(Prop.Name) <> "ITEM" Then
                                    Prop.SetValue(TheObject, Convert.ChangeType(myReader.Item(Prop.Name), Prop.PropertyType), Nothing)
                                End If
                            Catch
                            End Try
                        Next
                    Loop
                End Using
            End Using
            Return InfoList
        End Using
    Catch ex As Exception
        Return Nothing
    End Try
End Function

哦,等等,这里也有很多其他的变化!我无法想到你复制函数几乎和复制查询代码一样多,所以我做了一个循环。使用这些函数来创建IDbConnectionIDbCommand个对象,因为其余代码是相同的(并且它们实际上只是调用这些接口可用的函数)。

Private Function getConnection(connectionType As ConnectionType, connectionString As String) As IDbConnection
    Select Case connectionType
        Case ConnectionType.MsSql
            Return New SqlClient.SqlConnection(connectionString)
        Case ConnectionType.MsAccess
            Return New OleDb.OleDbConnection(connectionString)
        Case Else
            Return Nothing
    End Select
End Function

Private Function getCommand(connectionType As ConnectionType, commandString As String, connection As IDbConnection) As IDbCommand
    Select Case connectionType
        Case ConnectionType.MsSql
            Return New SqlClient.SqlCommand()
        Case ConnectionType.MsAccess
            Return New OleDb.OleDbCommand()
        Case Else
            Return Nothing
    End Select
End Function

Private Enum ConnectionType
    MsSql
    MsAccess
End Enum

(如果您要添加另一种连接类型,只要它实现这些接口就很简单。)

可以简化属性设置代码,假设日期是标准格式,则只需要一行来设置所有属性

Prop.SetValue(TheObject, Convert.ChangeType(myReader.Item(Prop.Name), Prop.PropertyType), Nothing)

此外,您可以看到没有理由在那里创建两个 ControlCaption个对象...

最后,您不需要显式关闭连接,因为您已经在使用块中正确地将其连接起来。