diff --git a/CS/Snoop/CollectorExts/CollectorExtElement.cs b/CS/Snoop/CollectorExts/CollectorExtElement.cs
index 664f9020a..0c9bcd9c8 100644
--- a/CS/Snoop/CollectorExts/CollectorExtElement.cs
+++ b/CS/Snoop/CollectorExts/CollectorExtElement.cs
@@ -25,13 +25,13 @@
using System;
using System.Linq;
using System.Collections;
+using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using RevitLookup.Snoop.Collectors;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
using RevitLookup.Snoop.Data;
-using String = System.String;
namespace RevitLookup.Snoop.CollectorExts
{
@@ -52,6 +52,7 @@ public CollectorExtElement()
.Where(x => Path.GetDirectoryName(x.Location) == baseDirectory)
.Where(x => x.GetName().Name.ToLower().Contains("revit"))
.SelectMany(x => x.GetTypes())
+ .Union(new [] {typeof(KeyValuePair<,>)})
.ToArray();
}
@@ -72,7 +73,7 @@ protected override void CollectEvent(object sender, CollectorEventArgs e)
private void Stream(ArrayList data, object elem)
{
- var thisElementTypes = types.Where(x => elem.GetType().IsSubclassOf(x) || elem.GetType() == x || x.IsAssignableFrom(elem.GetType())).ToList();
+ var thisElementTypes = types.Where(x => IsSnoopableType(x, elem)).ToList();
var streams = new IElementStream[]
{
@@ -83,9 +84,9 @@ private void Stream(ArrayList data, object elem)
new ExtensibleStorageEntityContentStream(m_app.ActiveUIDocument.Document, data, elem)
};
- foreach (Type type in thisElementTypes)
+ foreach (var type in thisElementTypes)
{
- data.Add(new Snoop.Data.ClassSeparator(type));
+ data.Add(new ClassSeparator(type));
foreach (var elementStream in streams)
elementStream.Stream(type);
@@ -96,6 +97,27 @@ private void Stream(ArrayList data, object elem)
StreamSimpleType(data, elem);
}
+ private static bool IsSnoopableType(Type type, object element)
+ {
+ var elementType = element.GetType();
+
+ if (type == elementType || elementType.IsSubclassOf(type) || type.IsAssignableFrom(elementType))
+ return true;
+
+ return type.IsGenericType && elementType.IsGenericType && IsSubclassOfRawGeneric(type, elementType);
+ }
+
+ private static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
+ while (toCheck != null && toCheck != typeof(object)) {
+ var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
+ if (generic == cur) {
+ return true;
+ }
+ toCheck = toCheck.BaseType;
+ }
+ return false;
+ }
+
private static void StreamElementExtensibleStorages(ArrayList data, Element elem)
{
var schemas = Schema.ListSchemas();
diff --git a/CS/Snoop/CollectorExts/DataFactory.cs b/CS/Snoop/CollectorExts/DataFactory.cs
index 84a64a730..189ddeb8d 100644
--- a/CS/Snoop/CollectorExts/DataFactory.cs
+++ b/CS/Snoop/CollectorExts/DataFactory.cs
@@ -17,8 +17,13 @@ public DataFactory(UIApplication application, object elem)
this.elem = elem;
}
- public Data.Data Create(MethodInfo methodInfo)
+ public Data.Data Create(MethodInfo mi)
{
+ var methodInfo = mi.ContainsGenericParameters ? elem.GetType().GetMethod(mi.Name, mi.GetParameters().Select(x => x.ParameterType).ToArray()) : mi;
+
+ if (methodInfo == null)
+ return null;
+
var declaringType = methodInfo.DeclaringType;
if (methodInfo.IsSpecialName || declaringType == null)
diff --git a/CS/Snoop/CollectorExts/ElementPropertiesStream.cs b/CS/Snoop/CollectorExts/ElementPropertiesStream.cs
index ca7f429f7..508081fd6 100644
--- a/CS/Snoop/CollectorExts/ElementPropertiesStream.cs
+++ b/CS/Snoop/CollectorExts/ElementPropertiesStream.cs
@@ -51,55 +51,62 @@ private PropertyInfo[] GetElementProperties( Type type )
.ToArray();
}
- private void AddPropertyToData( PropertyInfo pi )
+ private void AddPropertyToData(PropertyInfo pi)
{
- Type propertyType = pi.PropertyType;
+ var propertyInfo = pi.PropertyType.ContainsGenericParameters ? elem.GetType().GetProperty(pi.Name) : pi;
+
+ if (propertyInfo == null)
+ return;
+
+ var propertyType = propertyInfo.PropertyType;
- try
- {
- object propertyValue;
- if( pi.Name == "Geometry" )
- propertyValue = pi.GetValue( elem, new object[ 1 ] { new Options() } );
- else if( pi.Name == "BoundingBox" )
- propertyValue = pi.GetValue( elem, new object[ 1 ] { application.ActiveUIDocument.ActiveView } );
- else if( pi.Name == "Item" )
- propertyValue = pi.GetValue( elem, new object[ 1 ] { 0 } );
- else if( pi.Name == "Parameter" )
- return;
- else if( pi.Name == "PlanTopology" )
- return;
- else if( pi.Name == "PlanTopologies" && pi.GetMethod.GetParameters().Length != 0 )
- return;
- else
- propertyValue = pi.GetValue( elem );
+ try
+ {
+ object propertyValue;
+ if (propertyInfo.Name == "Geometry")
+ propertyValue = propertyInfo.GetValue(elem, new object[1] {new Options()});
+ else if (propertyInfo.Name == "BoundingBox")
+ propertyValue = propertyInfo.GetValue(elem, new object[1] {application.ActiveUIDocument.ActiveView});
+ else if (propertyInfo.Name == "Item")
+ propertyValue = propertyInfo.GetValue(elem, new object[1] {0});
+ else if (propertyInfo.Name == "Parameter")
+ return;
+ else if (propertyInfo.Name == "PlanTopology")
+ return;
+ else if (propertyInfo.Name == "PlanTopologies" && propertyInfo.GetMethod.GetParameters().Length != 0)
+ return;
+ else if (propertyType.ContainsGenericParameters)
+ propertyValue = elem.GetType().GetProperty(propertyInfo.Name)?.GetValue(elem);
+ else
+ propertyValue = propertyInfo.GetValue(elem);
- DataTypeInfoHelper.AddDataFromTypeInfo( application, pi, propertyType, propertyValue, elem, data );
+ DataTypeInfoHelper.AddDataFromTypeInfo(application, propertyInfo, propertyType, propertyValue, elem, data);
- var category = elem as Category;
- if( category != null && pi.Name == "Id" && category.Id.IntegerValue < 0 )
- {
- var bic = (BuiltInCategory) category.Id.IntegerValue;
+ var category = elem as Category;
+ if (category != null && propertyInfo.Name == "Id" && category.Id.IntegerValue < 0)
+ {
+ var bic = (BuiltInCategory) category.Id.IntegerValue;
- data.Add( new Snoop.Data.String( "BuiltInCategory", bic.ToString() ) );
- }
+ data.Add(new Snoop.Data.String("BuiltInCategory", bic.ToString()));
+ }
- }
- catch( ArgumentException ex )
- {
- data.Add( new Snoop.Data.Exception( pi.Name, ex ) );
- }
- 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 ) );
- }
+ }
+ catch (ArgumentException ex)
+ {
+ data.Add(new Snoop.Data.Exception(propertyInfo.Name, ex));
+ }
+ catch (TargetException ex)
+ {
+ data.Add(new Snoop.Data.Exception(propertyInfo.Name, ex));
+ }
+ catch (TargetInvocationException ex)
+ {
+ data.Add(new Snoop.Data.Exception(propertyInfo.Name, ex));
+ }
+ catch (TargetParameterCountException ex)
+ {
+ data.Add(new Snoop.Data.Exception(propertyInfo.Name, ex));
+ }
}
}
}
diff --git a/CS/Snoop/CollectorExts/ExtensibleStorageEntityContentStream.cs b/CS/Snoop/CollectorExts/ExtensibleStorageEntityContentStream.cs
index db1ec88d9..f05d99bbd 100644
--- a/CS/Snoop/CollectorExts/ExtensibleStorageEntityContentStream.cs
+++ b/CS/Snoop/CollectorExts/ExtensibleStorageEntityContentStream.cs
@@ -42,32 +42,32 @@ public void Stream( Type type )
StreamEntityFieldValue( field );
}
- private void StreamEntityFieldValue( Field field )
+ private void StreamEntityFieldValue(Field field)
{
- try
- {
- var getEntityValueMethod = GetEntityFieldValueMethod( field );
+ try
+ {
+ var getEntityValueMethod = GetEntityFieldValueMethod(field);
- var valueType = GetFieldValueType( field );
+ var valueType = GetFieldValueType(field);
- var genericGet = getEntityValueMethod.MakeGenericMethod( valueType );
+ var genericGet = getEntityValueMethod.MakeGenericMethod(valueType);
- //var unit = UnitUtils.GetValidDisplayUnits( field.UnitType ).First(); // 2020
+ var fieldSpecType = field.GetSpecTypeId();
- var unit = UnitUtils.GetValidUnits( field.GetSpecTypeId() ).First(); // 2021
+ var unit = UnitUtils.IsMeasurableSpec(fieldSpecType) ? UnitUtils.GetValidUnits(field.GetSpecTypeId()).First() : UnitTypeId.Custom;
- var parameters = getEntityValueMethod.GetParameters().Length == 1
- ? new object[] { field }
- : new object[] { field, unit };
+ var parameters = getEntityValueMethod.GetParameters().Length == 1
+ ? new object[] {field}
+ : new object[] {field, unit};
- var value = genericGet.Invoke( entity, parameters );
+ var value = genericGet.Invoke(entity, parameters);
- AddFieldValue( field, value );
- }
- catch( Exception ex )
- {
- data.Add( new Snoop.Data.Exception( field.FieldName, ex ) );
- }
+ AddFieldValue(field, value);
+ }
+ catch (Exception ex)
+ {
+ data.Add(new Data.Exception(field.FieldName, ex));
+ }
}
private Type GetFieldValueType( Field field )
@@ -97,7 +97,7 @@ private void AddFieldValue( Field field, object value )
try
{
if( field.ContainerType != ContainerType.Simple )
- data.Add( new Snoop.Data.Object( field.FieldName, value ) );
+ data.Add( new Snoop.Data.Enumerable( field.FieldName, value as IEnumerable ) );
else if( field.ValueType == typeof( double ) )
data.Add( new Snoop.Data.Double( field.FieldName, (double) value ) );
else if( field.ValueType == typeof( string ) )
@@ -125,40 +125,30 @@ private void AddFieldValue( Field field, object value )
}
}
- private MethodInfo GetEntityFieldValueMethod( Field field )
+ private static MethodInfo GetEntityFieldValueMethod(Field field)
{
- return typeof( Entity )
- .GetMethods( BindingFlags.Public | BindingFlags.Instance )
- .Where( x => x.Name == "Get" && x.IsGenericMethod )
- .Single( x => IsGetByFieldMethod( x, field ) );
+ return typeof(Entity)
+ .GetMethods(BindingFlags.Public | BindingFlags.Instance)
+ .Where(x => x.Name == nameof(Entity.Get) && x.IsGenericMethod)
+ .Single(x => IsGetByFieldMethod(x, field));
}
- private static bool IsGetByFieldMethod( MethodInfo methodInfo, Field field )
+ private static bool IsGetByFieldMethod(MethodInfo methodInfo, Field field)
{
- var parameters = methodInfo.GetParameters();
-
- if( field.ContainerType == ContainerType.Simple
- && (field.ValueType == typeof( XYZ )
- || field.ValueType == typeof( double )) )
- {
- //#pragma warning disable CS0618 // Revit 2021
- // warning CS0618: `DisplayUnitType` is obsolete:
- // This enumeration is deprecated in Revit 2021 and may be removed in a future version of Revit.
- // Please use the `ForgeTypeId` class instead.
- // Use constant members of the `UnitTypeId` class to replace uses of specific values of this enumeration.
+ var parameters = methodInfo.GetParameters();
+
+ var fieldSpecType = field.GetSpecTypeId();
- if( 2 == parameters.Length )
+ if (UnitUtils.IsMeasurableSpec(fieldSpecType) || fieldSpecType == SpecTypeId.Custom)
{
- ParameterInfo p1 = parameters.First();
- ParameterInfo p2 = parameters.Last();
- return p1.ParameterType == typeof( Field )
- && // (p2.ParameterType == typeof( DisplayUnitType ) || // Revit 2021
- p2.ParameterType == typeof( ForgeTypeId );
+ var firstParameter = parameters.First();
+
+ var lastParameter = parameters.Last();
+
+ return parameters.Length == 2 && firstParameter.ParameterType == typeof(Field) && lastParameter.ParameterType == typeof(ForgeTypeId);
}
- //#pragma warning restore CS0618 // Revit 2021
- }
- return parameters.Length == 1 && parameters.Single().ParameterType == typeof( Field );
+ return parameters.Length == 1 && parameters.Single().ParameterType == typeof(Field);
}
}
}
diff --git a/CS/Snoop/Data/ElementId.cs b/CS/Snoop/Data/ElementId.cs
index 7f21cd3dc..c6a7b9b52 100644
--- a/CS/Snoop/Data/ElementId.cs
+++ b/CS/Snoop/Data/ElementId.cs
@@ -22,63 +22,44 @@
//
#endregion // Header
-using System;
-using System.Windows.Forms;
-using System.Collections;
-
using Autodesk.Revit.DB;
namespace RevitLookup.Snoop.Data
{
- ///
- /// Snoop.Data class to hold and format an ElementId value.
- ///
-
- public class ElementId : Data
- {
- protected Autodesk.Revit.DB.ElementId m_val;
- protected Element m_elem = null;
-
- public
- ElementId(string label, Autodesk.Revit.DB.ElementId val, Document doc)
- : base(label)
- {
- m_val = val;
- try
- {
- if (val != Autodesk.Revit.DB.ElementId.InvalidElementId)
- m_elem = doc.GetElement(val); // TBD: strange signature!
- }
- catch (System.Exception)
- {
- m_elem = null;
- }
- }
-
- public override string
- StrValue()
+ ///
+ /// Snoop.Data class to hold and format an ElementId value.
+ ///
+
+ public class ElementId : Data
+ {
+ protected Autodesk.Revit.DB.ElementId m_val;
+ protected Element m_elem;
+
+ public ElementId(string label, Autodesk.Revit.DB.ElementId val, Document doc) : base(label)
{
- return Utils.ObjToLabelStr(m_elem);
+ m_val = val;
+
+ m_elem = doc.GetElement(val);
}
-
- public override bool
- HasDrillDown
+
+ public override string StrValue()
{
- get {
- if (m_elem == null)
- return false;
- else
- return true;
- }
+ if (m_elem != null)
+ return Utils.ObjToLabelStr(m_elem);
+
+ return m_val != Autodesk.Revit.DB.ElementId.InvalidElementId ? m_val.ToString() : Utils.ObjToLabelStr(null);
}
-
- public override void
- DrillDown()
+
+ public override bool HasDrillDown => m_elem != null;
+
+ public override void DrillDown()
{
- if (m_elem != null) {
- Snoop.Forms.Objects form = new Snoop.Forms.Objects(m_elem);
- form.ShowDialog();
- }
+ if (m_elem == null)
+ return;
+
+ var form = new Forms.Objects(m_elem);
+
+ form.ShowDialog();
}
- }
+ }
}
diff --git a/CS/Snoop/Data/Enumerable.cs b/CS/Snoop/Data/Enumerable.cs
index d459bfc77..380ce6f2f 100644
--- a/CS/Snoop/Data/Enumerable.cs
+++ b/CS/Snoop/Data/Enumerable.cs
@@ -71,7 +71,7 @@ public class Enumerable : Data
{
var elementId = iter.Current as Autodesk.Revit.DB.ElementId;
- if (elementId != null && doc != null)
+ if (elementId != null && doc != null && elementId.IntegerValue > 0)
m_objs.Add(doc.GetElement(elementId)); // it's more useful for user to view element rather than element id.
else
m_objs.Add(iter.Current);