It sounds like maybe you are looking for a way to identify your Types with some level of certainty. One way might be to use a custom attribute which will be easy to find and filter using Reflection.
Public Class RealMcCoy
Inherits Attribute
Public Property IsReal As Boolean
Public Sub New(b as Boolean)
IsReal = b
End Sub
End Class
<RealMcCoy(True)>
Public Class Patient
...
End Class
<RealMcCoy(True)>
Public Class Appointment
...
End Class
Now when iterating properties, check if it is the RealMcCoy
to see if it is one you want/need to drill into. Since the Attribute will be on the Type, there is an extra step to get each property's Type and poll that
Dim props As PropertyInfo() = myFoo.GetType.GetProperties
Dim pt As Type
For Each pi As PropertyInfo In props
pt = pi.PropertyType ' get the property type
Dim attr() As RealMcCoy =
DirectCast(pt.GetCustomAttributes(GetType(RealMcCoy), True), RealMcCoy())
If attr.Length > 0 Then
' bingo, baby...optional extra test:
If attr(0).IsReal Then
Console.Beep()
End If
Else
' skip this prop - its not a real mccoy
End If
Next
End Sub
It breaks if you add a Type and dont add the Attribute, but it is less breakable than having to update each Types for their constituent properties. A fake interface would be easier to query, but has the same drawback.
I am not sure I understand the issue of "gaming" things - are you afraid that some other Types will get picked up? Attributes would be hard to "game" since they are compiled into the assembly, still the above could be used to return a GUID (maybe one attached to the assembly?) rather than bool to provide some reassurance.
Absolute certainty will be hard to come by.
The RealMcCoy
attribute would probably not be applied to your top level types (PatientAppointment
) just the types (classes) which will be used as properties in other types. The object being a way to identify these easily.
Depending on how it is used, a dictionary or hashtable of TypeName-PropertyName pairs already identified as RealMcCoys might be useful so the whole Reflection process can be short circuited. Rather than adding on the fly, you might be able to build the list in its entirety up front as shown in this answer - see the RangeManager.BuildPropMap
procedure.
I am not so sure about the inheritance approach since you might want to actually use inheritance somewhere. An interface might work better: initially, its mere existence could be the trigger at the start, but could also be used to provide a service.
Simple test case:
' B and C classes are not tagged
Friend Class FooBar
Public Property Prop1 As PropA
Public Property Prop2 As PropB
Public Property Prop3 As PropC
Public Property Prop4 As PropD
Public Property Prop5 As PropE
End Class
Add a line to the for loop:
Dim f As New FooBar
' use instance:
Dim props As PropertyInfo() = f.GetType.GetProperties
Dim pt As Type
For Each pi As PropertyInfo In props
pt = pi.PropertyType
Dim attr() As RealMcCoy =
DirectCast(pt.GetCustomAttributes(GetType(RealMcCoy), True), RealMcCoy())
Console.WriteLine("Prop Name: {0}, prop type: {1}, IsRealMcCoy? {2}",
pi.Name, pt.Name, If(attr.Length > 0, "YES!", "no"))
Next
Output:
Prop Name: Prop1 prop type: PropA IsRealMcCoy? YES!
Prop Name: Prop2 prop type: PropB IsRealMcCoy? no
Prop Name: Prop3 prop type: PropC IsRealMcCoy? no
Prop Name: Prop4 prop type: PropD IsRealMcCoy? YES!
Prop Name: Prop5 prop type: PropE IsRealMcCoy? YES!