3

Is it possible to dynamically identify the closest common hierarchy or inheritance of two or more unknown typed objects? In other words, I'd like to test if, say, Integer and String have a common hierarchy, without knowing the objects I'm testing are going to be an Integer and String due to user selection. I found a C++ question posted that seems similar to my issue here: Check if two types are of the same template However, I'm not familiar with any VB.net equivalents of the answers posted there, and online translators simply provide an error when I attempt to translate them. So is this even possible in VB.net in the first place?

The closest to this action that I know of is the .IsAssignableFrom() function, but in my case I don't know what the parent class/interface/whatever is to test against in the first place. the above function is the only thing even remotely related to this issue that pops up on any search I do.

The context I need this is in the Revit API; I'm trying to see if user selected elements have a similar hierarchy/inheritance that is not the Object Type, and if so to allow an action, otherwise, give a warning dialog box.

EDIT: Due to the nature of the Revit API and the desired effects of my command, the users of my plugin could select anything in the model, and I'm not able to determine which of the MANY common ancestors I could be looking for to compare using IsAssignableFrom. I could test for the (I think universal) common ancestor of Element type, but I don't want to allow users to run the command if you select a wall and an element tag. I need to find the common ancestors of the user-selected elements and confirm that the closest common ancestor is below Element type in hierarchy.

For example, the room tag element in the API has a hierarchy sort of like this: Object -> Element -> SpatialElementTag -> RoomTag There may be more intermediate inheritances, but I'm not going to track them down in the API documentation. And then each element may have a slightly different ancestry. IsAssignableFrom would be great if I knew the base ancestry I wanted to test for.

TnTinMn's answer gives me the type of solution I'm looking for.

pmackni
  • 307
  • 3
  • 12
  • `IsAssignableFrom` is correct. What problems do you have in using it? – GSerg Jul 22 '19 at 19:29
  • That's if you know what parent type you're comparing to, correct? In my case, I want to take 2+ dynamically assigned types and determine if they have a common ancestor without knowing what that ancestor could be due to user selection of ANY element within the Revit API. I am effectively creating a xor filter based on class ancestry, without knowing if any common ancestry exists. Unless I'm mistaken, IsAssignableFrom does not work for this instance. I can edit my post to clarify this if need be. – pmackni Jul 22 '19 at 21:16
  • I misunderstood a little bit. `IsAssignableFrom` will let you know if one type inherits from another, directly or indirectly. It will not help if two types do not inherit from each other, but have a common inheritance root. – GSerg Jul 23 '19 at 06:30

1 Answers1

5

The Type.BaseType Property returns:

The Type from which the current Type directly inherits, or null if the current Type represents the Object class or an interface.

Using this information, it is possible to define an iterator to enumerate the inheritance tree.

Private Iterator Function SelfAndAncestors(srcType As Type) As IEnumerable(Of Type)
  Do Until srcType Is Nothing
    Yield srcType
    srcType = srcType.BaseType
  Loop
End Function

Now you can use the Enumerable.Intersect Method to find all common types in the inheritance between two ancestry enumerations and return the first common ancestry type.

Dim t1 As Type = GetType(Form)
Dim t2 As Type = GetType(UserControl)

Dim highestCommonAncestor As Type = Enumerable.Intersect(SelfAndAncestors(t1), SelfAndAncestors(t2)).First()

For this case, the highest common ancestor is ContainerControl.

TnTinMn
  • 11,522
  • 3
  • 18
  • 39