Skip to content

Commit

Permalink
Refactoring: removed legacy conditional compilation, make InvokeMetho…
Browse files Browse the repository at this point in the history
…d public, move LambdaParameterWrapper dependencies to LambdaParameterWrapperContext, minor naming conventions changes
  • Loading branch information
VitaliyMF committed Jan 4, 2024
1 parent 201de85 commit 94490a2
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 261 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Runtime parser for string expressions (formulas, method calls, properties/fields

NuGet | Windows x64 | Linux
--- | --- | ---
[![NuGet Release](https://img.shields.io/nuget/v/NReco.LambdaParser.svg)](https://www.nuget.org/packages/NReco.LambdaParser/) | [![AppVeyor](https://img.shields.io/appveyor/ci/nreco/lambdaparser/master.svg)](https://ci.appveyor.com/project/nreco/lambdaparser) | ![Tests](https://github.com/nreco/data/actions/workflows/dotnet-test.yml/badge.svg)
[![NuGet Release](https://img.shields.io/nuget/v/NReco.LambdaParser.svg)](https://www.nuget.org/packages/NReco.LambdaParser/) | [![AppVeyor](https://img.shields.io/appveyor/ci/nreco/lambdaparser/master.svg)](https://ci.appveyor.com/project/nreco/lambdaparser) | ![Tests](https://github.com/nreco/lambdaparser/actions/workflows/dotnet-test.yml/badge.svg)

* can be used in *any* .NET app: net45 (legacy .NET Framework apps), netstandard1.3 (.NET Core apps), netstandard2.0 (all modern .NET apps).
* any number of expression arguments (values can be provided as dictionary or by callback delegate)
Expand Down Expand Up @@ -43,6 +43,6 @@ var lambdaParser = new LambdaParser(valComparer);
NReco.LambdaParser is in production use at [SeekTable.com](https://www.seektable.com/) and [PivotData microservice](https://www.nrecosite.com/pivotdata_service.aspx) (used for user-defined calculated cube members: formulas, custom formatting).

## License
Copyright 2016-2023 Vitaliy Fedorchenko
Copyright 2016-2024 Vitaliy Fedorchenko and contributors

Distributed under the MIT license
73 changes: 21 additions & 52 deletions src/NReco.LambdaParser/InvokeMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,66 +18,45 @@
using System.Text;
using System.Reflection;

namespace NReco {
namespace NReco.Linq {

/// <summary>
/// Invoke object's method that is most compatible with provided arguments
/// </summary>
internal class InvokeMethod : Linq.IInvokeMethod {
public class InvokeMethod : IInvokeMethod {

internal readonly static InvokeMethod _Instance = new InvokeMethod();

public static Linq.IInvokeMethod Instance
{
get {
return _Instance;
}
}
public static Linq.IInvokeMethod Instance => _Instance;

Check warning on line 30 in src/NReco.LambdaParser/InvokeMethod.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'InvokeMethod.Instance'

protected MethodInfo FindMethod(object TargetObject, string MethodName, Type[] argTypes) {
if (TargetObject is Type) {
protected MethodInfo FindMethod(object targetObject, string methodName, Type[] argTypes) {

Check warning on line 32 in src/NReco.LambdaParser/InvokeMethod.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'InvokeMethod.FindMethod(object, string, Type[])'
if (targetObject is Type) {
// static method
#if NET40
return ((Type)TargetObject).GetMethod(MethodName, BindingFlags.Static | BindingFlags.Public);
#else
return ((Type)TargetObject).GetRuntimeMethod(MethodName, argTypes);
#endif
return ((Type)targetObject).GetRuntimeMethod(methodName, argTypes);
}
#if NET40
return TargetObject.GetType().GetMethod(MethodName, argTypes);
#else
return TargetObject.GetType().GetRuntimeMethod(MethodName, argTypes);
#endif
return targetObject.GetType().GetRuntimeMethod(methodName, argTypes);
}

protected IEnumerable<MethodInfo> GetAllMethods(object TargetObject) {
if (TargetObject is Type) {
#if NET40
return ((Type)TargetObject).GetMethods(BindingFlags.Static | BindingFlags.Public);
#else
return ((Type)TargetObject).GetRuntimeMethods();
#endif
protected IEnumerable<MethodInfo> GetAllMethods(object targetObject) {

Check warning on line 40 in src/NReco.LambdaParser/InvokeMethod.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'InvokeMethod.GetAllMethods(object)'
if (targetObject is Type) {
return ((Type)targetObject).GetRuntimeMethods();
}
#if NET40
return TargetObject.GetType().GetMethods();
#else
return TargetObject.GetType().GetRuntimeMethods();
#endif
return targetObject.GetType().GetRuntimeMethods();
}

public object Invoke(object TargetObject, string MethodName, object[] args) {
public object Invoke(object targetObject, string methodName, object[] args) {

Check warning on line 47 in src/NReco.LambdaParser/InvokeMethod.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'InvokeMethod.Invoke(object, string, object[])'
Type[] argTypes = new Type[args.Length];
for (int i = 0; i < argTypes.Length; i++)
argTypes[i] = args[i] != null ? args[i].GetType() : typeof(object);

// strict matching first
MethodInfo targetMethodInfo = FindMethod(TargetObject, MethodName, argTypes);
MethodInfo targetMethodInfo = FindMethod(targetObject, methodName, argTypes);
// fuzzy matching
if (targetMethodInfo==null) {
var methods = GetAllMethods(TargetObject);
var methods = GetAllMethods(targetObject);

foreach (var m in methods)
if (m.Name==MethodName &&
if (m.Name==methodName &&
m.GetParameters().Length == args.Length &&
CheckParamsCompatibility(m.GetParameters(), argTypes, args)) {
targetMethodInfo = m;
Expand All @@ -90,12 +69,12 @@ public static Linq.IInvokeMethod Instance
argTypeNames[i] = argTypes[i].Name;
string argTypeNamesStr = String.Join(",",argTypeNames);
throw new MissingMemberException(
(TargetObject is Type ? (Type)TargetObject : TargetObject.GetType()).FullName+"."+MethodName );
(targetObject is Type ? (Type)targetObject : targetObject.GetType()).FullName+"."+methodName );
}
object[] argValues = PrepareActualValues(MethodName,targetMethodInfo.GetParameters(),args);
object[] argValues = PrepareActualValues(methodName,targetMethodInfo.GetParameters(),args);
object res = null;
try {
res = targetMethodInfo.Invoke( TargetObject is Type ? null : TargetObject, argValues);
res = targetMethodInfo.Invoke( targetObject is Type ? null : targetObject, argValues);
} catch (TargetInvocationException tiEx) {
if (tiEx.InnerException!=null)
throw new Exception(tiEx.InnerException.Message, tiEx.InnerException);
Expand All @@ -107,11 +86,7 @@ public static Linq.IInvokeMethod Instance
}

internal static bool IsInstanceOfType(Type t, object val) {
#if NET40
return t.IsInstanceOfType(val);
#else
return val!=null && t.GetTypeInfo().IsAssignableFrom(val.GetType().GetTypeInfo());
#endif
}

protected bool CheckParamsCompatibility(ParameterInfo[] paramsInfo, Type[] types, object[] values) {

Check warning on line 92 in src/NReco.LambdaParser/InvokeMethod.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'InvokeMethod.CheckParamsCompatibility(ParameterInfo[], Type[], object[])'
Expand All @@ -121,13 +96,7 @@ public static Linq.IInvokeMethod Instance
if (IsInstanceOfType(paramType, val))
continue;
// null and reference types
if (val==null &&
#if NET40
!paramType.IsValueType
#else
!paramType.GetTypeInfo().IsValueType
#endif
)
if (val==null && !paramType.GetTypeInfo().IsValueType)
continue;
// possible autocast between generic/non-generic common types
try {
Expand All @@ -143,7 +112,7 @@ public static Linq.IInvokeMethod Instance
}


protected object[] PrepareActualValues(string MethodName, ParameterInfo[] paramsInfo, object[] values) {
protected object[] PrepareActualValues(string methodName, ParameterInfo[] paramsInfo, object[] values) {

Check warning on line 115 in src/NReco.LambdaParser/InvokeMethod.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'InvokeMethod.PrepareActualValues(string, ParameterInfo[], object[])'
object[] res = new object[paramsInfo.Length];
for (int i=0; i<paramsInfo.Length; i++) {
if (values[i]==null || IsInstanceOfType( paramsInfo[i].ParameterType, values[i])) {
Expand All @@ -156,7 +125,7 @@ public static Linq.IInvokeMethod Instance
} catch {
throw new InvalidCastException(
String.Format("Invoke method '{0}': cannot convert argument #{1} from {2} to {3}",
MethodName, i, values[i].GetType(), paramsInfo[i].ParameterType));
methodName, i, values[i].GetType(), paramsInfo[i].ParameterType));
}
}
return res;
Expand Down
Loading

0 comments on commit 94490a2

Please sign in to comment.