I'm a bit stuck right now in trying to determine the best solution to prevent an infinite recursion loop. Perhaps it's not exactly "recursion", but it's a set of function calls that I can pretty much guarantee will be calling each other indefinitely if I can't come up with a solution.
In trying to figure out how to explain the issue, it seems the best way I can come up with is to start with some simplified (and redacted) code. For this example, I'll use a Classroom and a Student.
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
So far, pretty straight forward. However, the problem comes in the fact that the same student may be tied to multiple classrooms. I want to have a similar method in the Student
object to be able to pull all related classrooms for that 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
So, my consternation at this point is, how do I prevent it from constantly looping back and forth between the classrooms and the students populating the same things over and over again in an infinite loop?
The only thing I can think to do is to set a Boolean variable somewhere that I can set to identify whether or not to keep drilling down. The problem is that my brain is a bit fried at the moment, and I can't figure out how to implement such a solution.
Some of the searching I've done also mentioned the possibility of some sort of "backtracking", which sounds cool, but doesn't seem very likely to work in this type of situation. Of course, I could be wrong on that, and I'd love to see any sort of implementation that is somehow capable of intelligently identifying if I'm just looping the same things over and over again.
What I'd like to see happen is the top-level Classroom
object creation should pick up its Student
objects, which should pick up any additional Classroom
objects to which they are associated, including each of those Classroom
object's Student
objects, and then it stops.
I hope that all makes sense. It's actually even more complicated than this as there are other similar objects that will be tied back to the top-level object (Classroom
), which should also follow the same basic rules - don't dig too deep into the "sub" records, and prevent an infinite recursive loop
If any clarification is necessary, please let me know. I truly appreciate any assistance you can provide.
答案 0 :(得分:0)
我想我可能知道如何解决这个问题,但我想对我的想法得到一些反馈。
如果我创建了一个接受布尔值(New
)的GetRelatedDetails
构造函数的重载,那么我最初可以调用它,并将该标志设置为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
方法时,也会进入GetClassroomStudents
或{ {1}},它只调用默认为GetStudentClassrooms
的{{1}}构造函数重载。这样,我猜它应该阻止它一遍又一遍地无条件地循环回来。
当然,我对实施此方法的最佳方式持开放态度,但我认为这是我现在要做的。