【问题标题】:VB.NET How To Prevent Infinite Recursion During Object PopulationVB.NET 如何在对象填充期间防止无限递归
【发布时间】:2016-10-20 20:10:44
【问题描述】:

我现在有点难以确定防止无限递归循环的最佳解决方案。也许它不是完全“递归”,但它是一组函数调用,如果我无法提出解决方案,我几乎可以保证它们会无限期地相互调用。

在试图弄清楚如何解释这个问题时,我能想到的最好方法似乎是从一些简化(和编辑)的代码开始。对于这个例子,我将使用一个教室和一个学生。

Public Class Classroom
    Public Property ClassroomID As Integer
    Public Property ClassroomDescription As String
    Public Property Students As List(Of Student)

    Public Sub New(ByVal ClassroomID As Integer)
        Initialize()
        GetClassroomDetail(ClassroomID)
    End Sub

    Public Sub GetClassroomDetail(ByVal ClassroomID As Integer)
        Dim Reader As SqlDataReader

        ' HERE'S WHERE I MAKE THE DATABASE CALL TO
        ' GET THE CLASSROOM RECORD DETAILS

        FillClassroomRecord(Reader)
    End Sub

    Private Sub FillClassroomRecord(Reader)
        While Reader.Read
            ClassroomID = CType(Reader("ClassroomID"), Integer)
            ClassroomDescription = CType(Reader("ClassroomDescription"), String)

            Students = GetClassroomStudents(ClassroomID)
        End While
    End Sub

    Private Function GetClassroomStudents(ByVal ClassroomID As Integer) As List(Of Student)
        Dim StudentData As DataTable
        Dim ClassroomStudents As New List(Of Student)

        ' I PULL A LIST OF STUDENTS RELATED TO THE SPECIFIC CLASSROOMID

        For Each StudentRow As DataRow In StudentData.Rows
            Dim NewStudent As New Student(CType(StudentRow("studentid"), Integer))

            ClassroomStudents.Add(NewStudent)
        Next StudentRow

        Return ClassroomStudents
    End Function
End Class

到目前为止,非常简单。然而,问题在于同一个学生可能被绑定到多个教室。我想在 Student 对象中使用类似的方法,以便能够为该学生提取所有相关的教室。

Public Class Student
    Public Property StudentID As Integer
    Public Property Name As String
    Public Property Classrooms As List(Of Classroom)
    ...
    Private Function GetStudentClassrooms(ByVal StudentID As Integer) As List(Of Classroom)
        Dim ClassroomData As DataTable
        Dim StudentClassrooms As New List(Of Classroom)

        ' PULL A LIST OF CLASSROOMS RELATED TO THE SPECIFIC STUDENTID

        For Each ClassroomRow As DataRow In ClassroomData.Rows
            Dim NewClassroom As New Classroom(CType(ClassroomRow("classroomid"), Integer))

            StudentClassrooms.Add(NewClassroom)
        Next ClassroomRow 

        Return StudentClassrooms
    End Function
End Class

那么,此时我的困惑是,我如何防止它在教室之间不断地来回循环,而学生们在无限循环中一遍又一遍地填充相同的东西?

我唯一能想到的就是在某个地方设置一个布尔变量,我可以设置它来确定是否继续向下钻取。问题是我现在脑子有点炸,不知道怎么实现这样的解决方案。

我所做的一些搜索还提到了某种“回溯”的可能性,这听起来很酷,但在这种情况下似乎不太可能起作用。当然,我可能是错的,我希望看到任何能够智能地识别我是否只是一遍又一遍地循环相同事物的实现。

我希望看到的是顶级 Classroom 对象创建应该拾取它的 Student 对象,它应该拾取与它们关联的任何其他 Classroom 对象,包括其中的每一个Classroom 对象的Student 对象,然后停止。

我希望一切都有意义。它实际上比这更复杂,因为还有其他类似的对象将被绑定回顶级对象 (Classroom),它们也应该遵循相同的基本规则——不要深入挖掘“子”记录,并防止无限递归循环

如果需要任何澄清,请告诉我。我非常感谢您能提供的任何帮助。

【问题讨论】:

  • 为什么ClassRoom 会对其他ClassRoom 对象感兴趣?
  • 如果我理解你的问题,答案是“不”。不是一个Classroom 需要知道另一个Classroom 存在本身。仅与Student 相关。
  • 你的课有点过头了。每个教室不需要学生列表 - 代表学生的 ID 列表就足够了。 GetClassroomStudents 正在创建新学生,而不是从他们的某些集合中获取当前学生的列表。如果您要迭代您的列表以标记一些缺席或设置成绩,那么它将针对与主/主要集合中不同的一组学生这样做。否则 linq 可以很容易地根据这个或那个属性提取集合。
  • 我想你可能误会了。 GetClassroomStudents实际上不是创建新学生,它只是为Classroom 中的每个现有Students 创建Student 对象的新实例。数据库在包含这些数据元素的两个表之间设置了一个多对多“索引”表,我用它来获取特定的Classroom/Student 对。如果我要使用Student 作为“顶级”来解决这个问题,我想拉出分配了Student 的所有Classrooms,以及其中的任何其他Students Classroom...
  • 这是一个多用户应用程序,学生和教室可以随时更新,因此需要为每个关于学生和教室的请求重新调用数据库,或者您可以保留所有运行时的数据客户端?

标签: vb.net recursion


【解决方案1】:

我想我可能知道如何解决这个问题,但我想就我的想法获得一些反馈。

如果我创建一个接受布尔值 (GetRelatedDetails) 的 New 构造函数的重载,那么我可以在初始时将该标志设置为 True 来调用它。除了将这个值沿链传递之外,几乎所有其他内容都应该保持不变。使用上面的例子,它看起来像这样:

Public Class Classroom
    Public Property ClassroomID As Integer
    Public Property ClassroomDescription As String
    Public Property Students As List(Of Student)

    Public Sub New(ByVal ClassroomID As Integer)
        Initialize()
        GetClassroomDetail(ClassroomID, False)
    End Sub

    ' OVERLOAD WITH BOOLEAN VALUE TO GET RELATED DETAILS
    Public Sub New(ByVal ClassroomID As Integer, ByVal GetRelatedDetails As Boolean)
        Initialize()
        GetClassroomDetail(ClassroomID, GetRelatedDetails)
    End Sub

    Public Sub GetClassroomDetail(ByVal ClassroomID As Integer, ByVal GetRelatedDetails As Boolean)
        Dim Reader As SqlDataReader

        ' HERE'S WHERE I MAKE THE CALL TO GET THE 
        ' CLASSROOM RECORD DETAILS FROM THE DATABASE

        FillClassroomRecord(Reader, GetRelatedDetails)
    End Sub

    Private Sub FillClassroomRecord(ByVal Reader As SqlDataReader, ByVal GetRelatedDetails As Boolean)
        While Reader.Read
            ClassroomID = CType(Reader("ClassroomID"), Integer)
            ClassroomDescription = CType(Reader("ClassroomDescription"), String)

            If GetRelatedDetails Then
                Students = GetClassroomStudents(ClassroomID)
            End If
        End While
    End Sub

    Private Function GetClassroomStudents(ByVal ClassroomID As Integer) As List(Of Student)
        Dim StudentData As DataTable
        Dim ClassroomStudents As New List(Of Student)

        ' I PULL A LIST OF STUDENTS RELATED TO THE SPECIFIC CLASSROOMID

        For Each StudentRow As DataRow In StudentData.Rows
            Dim NewStudent As New Student(CType(StudentRow("studentid"), Integer))

            ClassroomStudents.Add(NewStudent)
        Next StudentRow

        Return ClassroomStudents
    End Function
End Class

那么Student 对象的作用基本相同:

Public Class Student
    Public Property StudentID As Integer
    Public Property StudentName As String
    Public Property Classrooms As List(Of Classroom)

    Public Sub New(ByVal StudentID As Integer)
        Initialize()
        GetStudentDetail(StudentID, False)
    End Sub

    ' OVERLOAD WITH BOOLEAN VALUE TO GET RELATED DETAILS
    Public Sub New(ByVal StudentID As Integer, ByVal GetRelatedDetails As Boolean)
        Initialize()
        GetStudentDetail(StudentID, GetRelatedDetails)
    End Sub

    Public Sub GetStudentDetail(ByVal StudentID As Integer, ByVal GetRelatedDetails As Boolean)
        Dim Reader As SqlDataReader

        ' HERE'S WHERE I MAKE THE CALL TO GET THE 
        ' STUDENT RECORD DETAILS FROM THE DATABASE

        FillStudentRecord(Reader, GetRelatedDetails)
    End Sub

    Private Sub FillStudentRecord(ByVal Reader As SqlDataReader, ByVal GetRelatedDetails As Boolean)
        While Reader.Read
            StudentID = CType(Reader("StudentID"), Integer)
            StudentName = CType(Reader("StudentName"), String)

            If GetRelatedDetails Then
                Classrooms = GetStudentClassrooms(StudentID)
            End If
        End While
    End Sub

    Private Function GetStudentClassrooms(ByVal StudentID As Integer) As List(Of Classroom)
        Dim ClassroomData As DataTable
        Dim StudentClassrooms As New List(Of Classroom)

        ' PULL A LIST OF CLASSROOMS RELATED TO THE SPECIFIC STUDENTID

        For Each ClassroomRow As DataRow In ClassroomData.Rows
            Dim NewClassroom As New Classroom(CType(ClassroomRow("classroomid"), Integer))

            StudentClassrooms.Add(NewClassroom)
        Next ClassroomRow 

        Return StudentClassrooms
    End Function
End Class

您会注意到,即使我将 True 的值传递给初始对象,当它到达 Fill 方法并进入 GetClassroomStudentsGetStudentClassrooms 时,它也只是调用New 构造函数重载,默认为 False。这样,我猜它应该可以防止它一遍又一遍地无限循环返回相同的记录。

当然,我愿意接受任何其他关于最佳实施方式的建议或想法,但我认为这是我现在要做的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-20
    相关资源
    最近更新 更多