RevitLookup Reflection Cross-Version Compatibility

Today, I present a large and drastic contribution to RevitLookup from Andy @awmcc90 McCloskey of RevDev Studios that will help significantly in supporting both past and future releases of Revit:

Drastic Changes Making Use of Object Inspection via Reflection

This weekend, Andy @awmcc90 McCloskey of RevDev Studios submitted RevitLookup pull request #22 – Object inspection via Reflection.

The new functionality it incorporates will help significantly in supporting both past and future releases of Revit:

It includes drastic changes to the library to load object information directly from the assembly using .NET Reflection.

This makes more information available and the product more flexible.

Above all, the use of Reflection makes RevitLookup cross compatible with different versions of the Revit API.

In Andy's own words:

I think many people will greatly benefit from it.

In the past I have made small modifications to RevitLookup on GitHub. For the past few months I have been making some rather serious modifications to the source code in order to more fully explore every object that the API has to offer. This has primarily been to supplement my own add-in creation but also to get a better understanding of the underlying types of the API. Furthermore, I wanted to make RevitLookup work for any version of Revit, meaning I have been doing the majority of my changes via reflection.

I would like to contribute these changes to the project. Given how drastic the changes were, I wanted to give you a copy and see how you wanted to handle this.

Please refer to the commit summary below for more information on the changes made to individual modules.

Here is a screen snapshot snooping the properties of a roof using the Reflection enhanced version of RevitLookup:

RevitLookup using Reflection

Cross Version Compatibility

Andy's original version was compiled using the Revit 2016 API assemblies, yet the use of Reflection enables it to explore methods and properties added in Revit 2017 as well:

The version is based around 2016 Revit API libraries but that was just for compatibility. I don't particularly like handling separate projects so I resolve to wrap older commands and check to make sure they exist with whatever version of the API you are using and then choose the correct one. The version you are using will work as is for 2017 (from the most recent source code on github) and if you change the references to 2017 you can build and compile it fine as well.

Most of the additions from other users are completely obsolete at this point. Given everything available to the API object is now loaded directly from the assembly, we shouldn't be missing any information.

One feature that this does change is it simply gives you the name of the method or property directly from the library, whereas you were originally naming these specifically. I think I prefer this method because most of us using RevitLookup are doing it in order to do something else with the API, and it helps to have the exact name of the property and method when we go to start programming.

That handles most of the major changes. There are definitely some minor ones that I am missing but I think this is a good start.

Removal of Events and Unused Functionality

Functionality not required for the fundamental object inspection task has been removed:

I took out a several of the main commands, such as events, etc., because I was only interested in the element information. It shouldn't be too hard to piece those commands back in but wanted to make sure you knew. I was focused on the object inspection only.

Commit Summary

For the sake of completeness, here is the detailed commit summary of Andy's RevitLookup pull request #22 – Object inspection via Reflection:

Snoop / CollectorExts

Removed all modules spare two, the non abstract one which is the main worker of loading information via reflection. In general, I felt like it was a lot of code which needed to be specifically typed out in order to get parameters and method values that were already available. The new worker is very simple: when the collect event is called, we pass the object to the worker, the worker determines which types the object is associated with and places those in a list. Then we loop through each type and collect properties and methods that meet certain requirements, for each type:

We avoid making any changes to the document by invoking the methods in a try statement, and given we are outside of a transaction we catch any error that it would throw due to that. I did a simple (and I mean simple) check of what parameters we have already seen so that we don't continue to log duplicate information in the snoop dialog. I considered leaving all the properties and methods in for every type but it made the list of information very long and I wasn't sure how much I benefited from showing all that information.

Certain specific properties and methods that I wanted, such as element geometry and boundary segments, I had to add on a case by case basis but even this is much more efficient because we still don't require separate methods for each type. We can continue to update the list of specific properties and methods that have parameter inputs as an ongoing work.

Utils

I thinned out the Utils class to remove anything that we no longer needed. The changes here were minor.

Tests

I had to remove the vast majority of the tests given they were no longer required and more importantly the methods that they called no longer existed.

File Changes

Here is the list of files modified (M), replaced (R) and deleted (D).

As you can see, quite a number have been completely removed, significantly simplifying the project with a simultaneous enhancement of functionality:

Download

The new functionality is provided in RevitLookup release 2017.0.0.14 and later versions.

If you would like to access any part of the functionality that was considered unimportant and removed in this release, please feel free to grab it from release 2017.0.0.13.

I am also perfectly happy to restore code that was removed and that you would like preserved. Simply create a pull request for that, explain your need and motivation, and I will gladly merge it back again.

RevDev Studios

RevDev Studios provides custom add-in development services for Revit.

I guess I really ought to add a comment about them to the post on finding a development partner, or update that post in general.

Addendum – Never Catch All Exceptions

Compilation of RevitLookup release 2017.0.0.14 discussed above causes two warnings CS0168 in CollectorExtElement.cs saying, "The variable 'ex' is declared but never used" in exception handlers like this:

  catchException ex )
  {
    // Probably is that this specific element
    // doesn't have the property - ignore
    //data.Add(new Snoop.Data.Exception(pi.Name, ex));
  }

However, you should never, ever, catch all exceptions.

Andy very kindly fixed that as well, submitting pull request #23 – catching proper exceptions for reflection invocation.

Now the exception handler looks like this instead, catching specific exceptions and leaving the really unexpected, exceptional exceptions untouched:

  catch (TargetException ex)
  {
    data.Add(new Snoop.Data.Exception(pi.Name, ex));
  }
  catch (TargetInvocationException ex)
  {
    data.Add(new Snoop.Data.Exception(pi.Name, ex));
  }
  catch (TargetParameterCountException ex)
  {
    data.Add(new Snoop.Data.Exception(pi.Name, ex));
  }

RevitLookup release 2017.0.0.15 with this fix integrated no longer violates this recommendation and compiles with zero warnings.

Thanks again to Andy!