Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prototyping reflection of external libraries #1132

Merged
merged 28 commits into from
Aug 28, 2019

Conversation

epignatelli
Copy link
Member

@epignatelli epignatelli commented Aug 8, 2019

There is no actual code-wise dependency.
Although, to test the prototype, you need to switch to the correspondent (identically named) branches in the BHoM_UI and the Grasshopper_Toolkit, and this pr from the Numpy_Toolkit: BHoM/Numpy_Toolkit#2

Issues addressed by this PR

Closes #1131
This pr is adding a way to reflect assemblies that are not BHoM-compliant, but can be useful in the BHoM workflow.
I have put together a quick wiki for a more exhaustive explanation of the principles I followed, and how to implement another in the future: https://github.com/BHoM/documentation/wiki/The-%60External%60-class

The other main change is this pr is the migration of some of the methods from the UI, that was not really in the best place.
I will put specific comments on the diffs to explain them, I think it is easier to explain and review without missing something.

Test files

The test comes with the PR on the Numpy_Toolkit: BHoM/Numpy_Toolkit#2

Changelog

  • Migrated GroupMethodsByName from the UI to the Data_Engine and renamed it to GroupByName, since it is a generic method
  • Refactored the UI method CompileFunction to Engine.Reflection.Convert.ToFunc in order to transform any delegate to a Func<object[], object>
  • Provide a way to expose instance methods, and any method that returns void
  • Migrate Engine.Serialiser.Create.MethodBase to Engine.Reflection.Create.MethodBase. The List<string> paramTypes now is the list of name of the types, rather than their json representation
  • Added a way to create MethodBases via a List<Type> as well, for robustness and performance
  • Migrate Engine.Serialiser.Create.MethodInfo to Engine.Reflection.Create.MethodInfo
  • Add the IsExposed method to centralise the check of which methods to expose to the UIs.
  • Add Engine.Reflection.Query.ExternalMethodList as a way to collect methods from external libraries
  • Add ability to collect methods declared in nested classes

@epignatelli epignatelli added the type:feature New capability or enhancement label Aug 8, 2019
@epignatelli epignatelli added this to the BHoM 2.4 β MVP milestone Aug 8, 2019
@epignatelli epignatelli self-assigned this Aug 8, 2019
@epignatelli epignatelli changed the title BHoM_Engine: Prototyping reflection of external libraries [WIP] BHoM_Engine: Prototyping reflection of external libraries Aug 8, 2019
@al-fisher al-fisher added the status:WIP PR in progress and still in draft, not ready for formal review label Aug 12, 2019
return method;

// So, let's try the other overload
return MethodBase(type, methodName, paramTypes.Select(x => x.Name).ToList());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uses the old overload in case the new fails when dealing with generic types (I believe around 10% of the cases, maybe less)

/**** Public Methods ****/
/*************************************/

public static MethodInfo MethodInfo(this Type declaringType, string methodName, List<Type> paramTypes)
Copy link
Member Author

@epignatelli epignatelli Aug 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migration from the BHoM_UI

[Description("Returns the specific type from a type that contains generic parameters")]
[Input("method", "The generic type")]
[Output("type", "The specific type constructed from the generic one")]
public static MethodInfo MakeStatic(this MethodInfo method)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is not correct, because I was not really able to convert an instance method into a static method.. Thus, it is not really used. We may consider removing it altogether.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I suppose you now have figured out why it cannot work after your work on the UI side.
I would suggest to remove this then. No point on leaving public methods that don't work in the code.

/**** Public Methods - Interfaces ****/
/***************************************************/

public static bool IIsExposed(this object obj)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one centralises the check of what to reflect to the UIs.
The current approach spreads around a combination of IsNotImplemented and IsDeprecated.

@@ -59,6 +59,18 @@ public static List<MethodBase> AllMethodList()
return m_AllMethodList;
}

/***************************************************/

public static List<MethodBase> ExternalMethodList()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one collects the methods that come from external libraries.

I have chosen to store the methods into a standalone field to avoid contaminating the other ones.
The reason is that the namespace of the methods the field stores do not start with BH.

/**** Public Methods ****/
/***************************************************/

public static List<MethodInfo> NestedMethods(this Type type)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This add the feature to retrieve methods declared in nested classes

@@ -88,18 +88,20 @@ public override MethodBase Deserialize(BsonDeserializationContext context, BsonD
bsonReader.ReadName();
string methodName = bsonReader.ReadString();

List<string> paramTypes = new List<string>();
List<string> paramTypesJson = new List<string>();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this improves the clarity of the variable: it's not the name of the type, it is its json representation

bsonReader.ReadEndArray();

context.Reader.ReadEndDocument();

try
{
MethodBase method = Create.MethodBase((Type)Convert.FromJson(typeName), methodName, paramTypes);
List<Type> types = paramTypesJson.Select(x => Convert.FromJson(x)).Cast<Type>().ToList();
MethodBase method = Create.MethodBase((Type)Convert.FromJson(typeName), methodName, types); // type overload
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing the actual types to the reflection engine. In the current master, Create.MethodBase lies in the Serialisation_Engine exactly because paramTypes is a json string, and not the name of the method.

By deserialising the types before the method call allows us to move the Create.MethodBase in its correct namespase: Engine.Reflection.

Copy link
Member Author

@epignatelli epignatelli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some comments in the code to help reviewing this pr

@epignatelli epignatelli marked this pull request as ready for review August 16, 2019 13:44
@epignatelli epignatelli requested a review from rwemay as a code owner August 16, 2019 13:44
@epignatelli epignatelli removed the status:WIP PR in progress and still in draft, not ready for formal review label Aug 16, 2019
@epignatelli epignatelli changed the title [WIP] BHoM_Engine: Prototyping reflection of external libraries BHoM_Engine: Prototyping reflection of external libraries Aug 19, 2019
Copy link
Member

@adecler adecler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Globally happy with the changes. Well done :-)
Just one thing to change :-)

[Description("Returns the specific type from a type that contains generic parameters")]
[Input("method", "The generic type")]
[Output("type", "The specific type constructed from the generic one")]
public static MethodInfo MakeStatic(this MethodInfo method)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I suppose you now have figured out why it cannot work after your work on the UI side.
I would suggest to remove this then. No point on leaving public methods that don't work in the code.

@epignatelli
Copy link
Member Author

Thanks @adecler - yeah, that method doesn't have reason to exist.
Removed in the last commit.

Copy link
Member

@adecler adecler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All look good to me. 👍

@adecler adecler merged commit b835317 into master Aug 28, 2019
@adecler adecler deleted the BHoM_Engine-#1131-ReflectingExternalLibraries branch August 28, 2019 02:03
@FraserGreenroyd FraserGreenroyd changed the title BHoM_Engine: Prototyping reflection of external libraries Prototyping reflection of external libraries Sep 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:feature New capability or enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BHoM_Engine: Prototyping reflection of external libraries
3 participants