-
Notifications
You must be signed in to change notification settings - Fork 15
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
Changes from all commits
2004f56
9188e17
fe70cce
63ac9a9
94a65b4
e1565ba
ddbd5e6
598a2b8
0222033
d3b8316
7df300d
4936892
4b55f13
ee037bc
3841f34
5a16b10
cfbf766
9fbf089
099556c
0acb971
cef75d2
b84f01d
4c1ef99
266b17c
a84af06
6671d60
31c59fd
54b498f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
* This file is part of the Buildings and Habitats object Model (BHoM) | ||
* Copyright (c) 2015 - 2018, the respective contributors. All rights reserved. | ||
* | ||
* Each contributor holds copyright over their respective contributions. | ||
* The project versioning (Git) records all such contribution source information. | ||
* | ||
* | ||
* The BHoM is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Lesser General Public License as published by | ||
* the Free Software Foundation, either version 3.0 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* The BHoM is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public License | ||
* along with this code. If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>. | ||
*/ | ||
|
||
using BH.oM.Data.Collections; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace BH.Engine.Data | ||
{ | ||
public static partial class Modify | ||
{ | ||
/*************************************/ | ||
/**** Public Methods ****/ | ||
/*************************************/ | ||
|
||
public static Tree<T> GroupByName<T>(this Tree<T> tree) | ||
{ | ||
if (tree.Children.Count > 0) | ||
{ | ||
if (tree.Children.Values.Any(x => x.Value != null)) | ||
{ | ||
var groups = tree.Children.GroupBy(x => | ||
{ | ||
int index = x.Key.IndexOf('('); | ||
if (index > 0) | ||
return x.Key.Substring(0, index); | ||
else | ||
return x.Key; | ||
}); | ||
|
||
if (groups.Count() > 1) | ||
{ | ||
Dictionary<string, Tree<T>> children = new Dictionary<string, Tree<T>>(); | ||
foreach (var group in groups) | ||
{ | ||
if (group.Count() == 1) | ||
{ | ||
if (group.First().Value.Value == null) | ||
children.Add(group.Key, group.First().Value); | ||
else | ||
children.Add(group.Key, new Tree<T> { Name = group.Key, Value = group.First().Value.Value }); | ||
} | ||
else | ||
children.Add(group.Key, new Tree<T> { Name = group.Key, Children = group.ToDictionary(x => x.Key, x => x.Value) }); | ||
} | ||
tree.Children = children; | ||
} | ||
} | ||
else | ||
{ | ||
foreach (var child in tree.Children.Values) | ||
GroupByName(child); | ||
} | ||
} | ||
|
||
return tree; | ||
} | ||
|
||
/*************************************/ | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
/* | ||
* This file is part of the Buildings and Habitats object Model (BHoM) | ||
* Copyright (c) 2015 - 2019, the respective contributors. All rights reserved. | ||
* | ||
* Each contributor holds copyright over their respective contributions. | ||
* The project versioning (Git) records all such contribution source information. | ||
* | ||
* | ||
* The BHoM is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Lesser General Public License as published by | ||
* the Free Software Foundation, either version 3.0 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* The BHoM is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public License | ||
* along with this code. If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>. | ||
*/ | ||
|
||
using System; | ||
using System.Linq; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
|
||
namespace BH.Engine.Reflection | ||
{ | ||
public static partial class Convert | ||
{ | ||
/***************************************************/ | ||
/**** Public Methods ****/ | ||
/***************************************************/ | ||
|
||
|
||
public static Func<object[], object> ToFunc(this MethodBase method) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This set of methods are the port of It has now been refactored into a |
||
{ | ||
if (method is MethodInfo) | ||
return ((MethodInfo)method).ToFunc(); | ||
else if (method is ConstructorInfo) | ||
return ((ConstructorInfo)method).ToFunc(); | ||
return null; | ||
} | ||
|
||
/***************************************************/ | ||
|
||
public static Func<object[], object> ToFunc(this MethodInfo method) | ||
{ | ||
ParameterExpression lambdaInput = Expression.Parameter(typeof(object[]), "x"); | ||
Expression[] inputs = method.GetParameters().Select((x, i) => Expression.Convert(Expression.ArrayIndex(lambdaInput, Expression.Constant(i)), x.ParameterType)).ToArray(); | ||
|
||
MethodCallExpression methodExpression; | ||
if (method.IsStatic) | ||
{ | ||
methodExpression = Expression.Call(method, inputs); | ||
if (method.ReturnType == typeof(void)) | ||
return Expression.Lambda<Action<object[]>>(Expression.Convert(methodExpression, typeof(void)), lambdaInput).Compile().ToFunc(); | ||
else | ||
return Expression.Lambda<Func<object[], object>>(Expression.Convert(methodExpression, typeof(object)), lambdaInput).Compile(); | ||
} | ||
else | ||
{ | ||
ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance"); | ||
Expression instanceInput = Expression.Convert(instanceParameter, method.DeclaringType); | ||
methodExpression = Expression.Call(instanceInput, method, inputs); | ||
|
||
if (method.ReturnType == typeof(void)) | ||
{ | ||
return Expression.Lambda<Action<object, object[]>>( | ||
Expression.Convert(methodExpression, typeof(void)), | ||
new ParameterExpression[] { instanceParameter, lambdaInput } | ||
).Compile().ToFunc(); | ||
} | ||
else | ||
{ | ||
return Expression.Lambda<Func<object, object[], object>>( | ||
Expression.Convert(methodExpression, typeof(object)), | ||
new ParameterExpression[] { instanceParameter, lambdaInput } | ||
).Compile().ToFunc(); | ||
} | ||
} | ||
} | ||
|
||
/***************************************************/ | ||
|
||
public static Func<object[], object> ToFunc(this ConstructorInfo ctor) | ||
{ | ||
ParameterExpression lambdaInput = Expression.Parameter(typeof(object[]), "x"); | ||
Expression[] inputs = ctor.GetParameters().Select((x, i) => Expression.Convert(Expression.ArrayIndex(lambdaInput, Expression.Constant(i)), x.ParameterType)).ToArray(); | ||
NewExpression constructorExpression = Expression.New(ctor as ConstructorInfo, inputs); | ||
return Expression.Lambda<Func<object[], object>>(Expression.Convert(constructorExpression, typeof(object)), lambdaInput).Compile(); | ||
} | ||
|
||
/***************************************************/ | ||
|
||
public static Func<object[], object> ToFunc(this Action<object[]> act) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one solves BHoM/BHoM_UI#118 |
||
{ | ||
return inputs => { act(inputs); return true; }; | ||
} | ||
|
||
/***************************************************/ | ||
|
||
public static Func<object[], object> ToFunc(this Func<object, object[], object> func) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one solves the convergence to the |
||
{ | ||
return inputs => { return func(inputs[0], inputs); }; | ||
} | ||
|
||
/***************************************************/ | ||
|
||
public static Func<object[], object> ToFunc(this Action<object, object[]> act) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one solves BHoM/BHoM_UI#118 for instance methods |
||
{ | ||
return inputs => { act(inputs[0], inputs); return true; }; | ||
} | ||
|
||
/***************************************************/ | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,7 +33,7 @@ public static partial class Create | |
/**** Public Methods ****/ | ||
/*******************************************/ | ||
|
||
public static MethodBase MethodBase(Type type, string methodName, List<string> paramTypes) | ||
public static MethodBase MethodBase(Type type, string methodName, List<string> paramTypeNames) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change is necessary to solve the dependency between the |
||
{ | ||
List<MethodBase> methods; | ||
if (methodName == ".ctor") | ||
|
@@ -48,12 +48,12 @@ public static MethodBase MethodBase(Type type, string methodName, List<string> p | |
if (method.Name == methodName) | ||
{ | ||
ParameterInfo[] parameters = method.ParametersWithConstraints(); | ||
if (parameters.Length == paramTypes.Count) | ||
if (parameters.Length == paramTypeNames.Count) | ||
{ | ||
bool matching = true; | ||
List<string> names = parameters.Select(x => Convert.ToJson(x.ParameterType)).ToList(); | ||
for (int i = 0; i < paramTypes.Count; i++) | ||
matching &= names[i] == paramTypes[i]; | ||
List<string> names = parameters.Select(x => x.ParameterType.Name).ToList(); | ||
for (int i = 0; i < paramTypeNames.Count; i++) | ||
matching &= names[i] == paramTypeNames[i]; | ||
|
||
if (matching) | ||
{ | ||
|
@@ -66,5 +66,25 @@ public static MethodBase MethodBase(Type type, string methodName, List<string> p | |
} | ||
|
||
/*******************************************/ | ||
|
||
public static MethodBase MethodBase(Type type, string methodName, List<Type> paramTypes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method improves the retrieval of Although, it fails on generic types, since we compile the methods on the constraints of the generic types, rather than on the generic types themselves. It also raises #1138 |
||
{ | ||
MethodBase method; | ||
if (methodName == ".ctor") | ||
method = type.GetConstructor(paramTypes.ToArray()); | ||
else | ||
method = type.GetMethod(methodName, paramTypes.ToArray()); | ||
|
||
// the above will return null if the type is a generic type | ||
// that is because we serialise a generic method with its constraints | ||
// rather than serialising the generics | ||
if (method != null) | ||
return method; | ||
|
||
// So, let's try the other overload | ||
return MethodBase(type, methodName, paramTypes.Select(x => x.Name).ToList()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) |
||
} | ||
|
||
/*******************************************/ | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
* This file is part of the Buildings and Habitats object Model (BHoM) | ||
* Copyright (c) 2015 - 2018, the respective contributors. All rights reserved. | ||
* | ||
* Each contributor holds copyright over their respective contributions. | ||
* The project versioning (Git) records all such contribution source information. | ||
* | ||
* | ||
* The BHoM is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Lesser General Public License as published by | ||
* the Free Software Foundation, either version 3.0 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* The BHoM is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public License | ||
* along with this code. If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>. | ||
*/ | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace BH.Engine.Reflection | ||
{ | ||
public static partial class Create | ||
{ | ||
/*************************************/ | ||
/**** Public Methods ****/ | ||
/*************************************/ | ||
|
||
public static MethodInfo MethodInfo(this Type declaringType, string methodName, List<Type> paramTypes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Migration from the BHoM_UI |
||
{ | ||
MethodInfo foundMethod = null; | ||
List<MethodInfo> methods = declaringType.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly).ToList(); | ||
|
||
for (int k = 0; k < methods.Count; k++) | ||
{ | ||
MethodInfo method = methods[k]; | ||
|
||
if (method.Name == methodName) | ||
{ | ||
ParameterInfo[] parameters = method.GetParameters(); | ||
if (parameters.Length == paramTypes.Count) | ||
{ | ||
if (method.ContainsGenericParameters) | ||
{ | ||
Type[] generics = method.GetGenericArguments().Select(x => x.MakeFromGeneric()).ToArray(); | ||
method = method.MakeGenericMethod(generics); | ||
parameters = method.GetParameters(); | ||
} | ||
|
||
bool matching = true; | ||
for (int i = 0; i < paramTypes.Count; i++) | ||
{ | ||
matching &= (paramTypes[i] == null || parameters[i].ParameterType == paramTypes[i]); | ||
} | ||
if (matching) | ||
{ | ||
foundMethod = method; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
return foundMethod; | ||
} | ||
|
||
/*************************************/ | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method has been migrated from the UI: https://github.com/BHoM/BHoM_UI/blob/2ad2b8a3a7c1a27596a5c88097da34d28636e8f8/UI_Engine/Modify/GroupMethodsByName.cs#L39
Old:
New:
Note that the name
MethodBase
was actually used as the name of a generic parameter, and was not a real specialisation of a generic method.