Skip to content

Commit f23748d

Browse files
committed
#98 evaluate methods names methods groups (overrides) and try to call the good one when necessary
1 parent 12ff9fb commit f23748d

File tree

2 files changed

+122
-8
lines changed

2 files changed

+122
-8
lines changed

CodingSeb.ExpressionEvaluator.Tests/ExpressionEvaluatorTests.cs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2474,7 +2474,7 @@ ExpressionEvaluator evaluatorForMethodArgs()
24742474
.Returns(typeof(List<Regex>))
24752475
.SetCategory("Bug resolution");
24762476

2477-
// For bug #65
2477+
#region For bug #65
24782478
var Persons = new List<Person2>() { new Person2() { Code = "QT00010", Name = "Pedrito", Number = 11.11m },
24792479
new Person2() { Code = "QT00011", Name = "Pablito", Number = 12.11m }};
24802480

@@ -2502,9 +2502,9 @@ ExpressionEvaluator evaluatorForMethodArgs()
25022502
.Returns(11.11m)
25032503
.SetCategory("Bug resolution");
25042504

2505-
// end of bug #65
2505+
#endregion
25062506

2507-
// For Issue Manage nested class and enum #95
2507+
#region For Issue Manage nested class and enum #95
25082508

25092509
yield return new TestCaseData(new ExpressionEvaluator()
25102510
, "Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)"
@@ -2520,7 +2520,39 @@ ExpressionEvaluator evaluatorForMethodArgs()
25202520
.SetCategory("Bug resolution")
25212521
.SetCategory("NestedType");
25222522

2523-
// end of issue #95
2523+
#endregion
2524+
2525+
#region For issue #98 Evaluate methods names as delegates
2526+
2527+
yield return new TestCaseData(new ExpressionEvaluator()
2528+
, "Array.ConvertAll(\"1,2,3,4,5,6,-1\".Split(','), Int32.Parse).Min()"
2529+
, null)
2530+
.Returns(-1)
2531+
.SetCategory("Bug resolution")
2532+
.SetCategory("MethodNameAsDelegates");
2533+
2534+
yield return new TestCaseData(new ExpressionEvaluator()
2535+
, "Array.ConvertAll<string,int>(\"1,2,3,4,5,6,-1\".Split(','), Int32.Parse).Min()"
2536+
, null)
2537+
.Returns(-1)
2538+
.SetCategory("Bug resolution")
2539+
.SetCategory("MethodNameAsDelegates");
2540+
2541+
yield return new TestCaseData(new ExpressionEvaluator()
2542+
, "Array.ConvertAll(\"1,2,3,4,5,6,-1\".Split(','), s => Int32.Parse(s)).Min()"
2543+
, null)
2544+
.Returns(-1)
2545+
.SetCategory("Bug resolution")
2546+
.SetCategory("MethodNameAsDelegates");
2547+
2548+
yield return new TestCaseData(new ExpressionEvaluator()
2549+
, "(() => { var m = int.Parse; return m(\"5\"); })()"
2550+
, null)
2551+
.Returns(5)
2552+
.SetCategory("Bug resolution")
2553+
.SetCategory("MethodNameAsDelegates");
2554+
2555+
#endregion
25242556

25252557
#endregion
25262558
}

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
using System.Globalization;
1616
using System.Linq;
1717
using System.Reflection;
18+
using System.Runtime.CompilerServices;
1819
using System.Runtime.InteropServices;
1920
using System.Text;
2021
using System.Text.RegularExpressions;
21-
using System.Runtime.CompilerServices;
2222

2323
namespace CodingSeb.ExpressionEvaluator
2424
{
@@ -1772,7 +1772,7 @@ void InitSimpleObjet(object element, List<string> initArgs)
17721772
int typeIndex = 0;
17731773
Type type = EvaluateType(completeName + genericTypes, ref typeIndex);
17741774

1775-
if (type == null || typeIndex > 0 && typeIndex < completeName.Length)
1775+
if (type == null || (typeIndex > 0 && typeIndex < completeName.Length))
17761776
throw new ExpressionEvaluatorSyntaxErrorException($"Type or class {completeName}{genericTypes} is unknown");
17771777

17781778
void Init(object element, List<string> initArgs)
@@ -2159,6 +2159,22 @@ where method.GetParameters()[0].ParameterType == objType // static extMethod(thi
21592159
{
21602160
stack.Push(delegateVar.DynamicInvoke(funcArgs.ConvertAll(Evaluate).ToArray()));
21612161
}
2162+
else if (Variables.TryGetValue(varFuncName, out o) && o is MethodsGroupEncaps methodsGroupEncaps)
2163+
{
2164+
List<object> args = funcArgs.ConvertAll(Evaluate);
2165+
List<object> modifiedArgs= null;
2166+
MethodInfo methodInfo = null;
2167+
2168+
for (int m = 0; methodInfo == null && m < methodsGroupEncaps.MethodsGroup.Length; m++)
2169+
{
2170+
modifiedArgs = new List<object>(args);
2171+
2172+
methodInfo = TryToCastMethodParametersToMakeItCallable(methodsGroupEncaps.MethodsGroup[m], modifiedArgs, genericsTypes, new Type[0], methodsGroupEncaps.ContainerObject);
2173+
}
2174+
2175+
if(methodInfo != null)
2176+
stack.Push(methodInfo.Invoke(methodsGroupEncaps.ContainerObject, modifiedArgs?.ToArray()));
2177+
}
21622178
else
21632179
{
21642180
FunctionEvaluationEventArg functionEvaluationEventArg = new FunctionEvaluationEventArg(varFuncName, funcArgs, this, genericTypes: genericsTypes, evaluateGenericTypes: GetConcreteTypes);
@@ -2249,6 +2265,20 @@ where method.GetParameters()[0].ParameterType == objType // static extMethod(thi
22492265
if (member == null && !isDynamic)
22502266
member = objType.GetField(varFuncName, flag);
22512267

2268+
if (member == null && !isDynamic)
2269+
{
2270+
MethodInfo[] methodsGroup = objType.GetMember(varFuncName, flag).OfType<MethodInfo>().ToArray();
2271+
2272+
if(methodsGroup.Length > 0)
2273+
{
2274+
varValue = new MethodsGroupEncaps()
2275+
{
2276+
ContainerObject = obj,
2277+
MethodsGroup = methodsGroup
2278+
};
2279+
}
2280+
}
2281+
22522282
bool pushVarValue = true;
22532283

22542284
if (isDynamic)
@@ -3392,6 +3422,8 @@ protected virtual MethodInfo TryToCastMethodParametersToMakeItCallable(MethodInf
33923422
{
33933423
MethodInfo methodInfo = null;
33943424

3425+
MethodInfo oldMethodInfo = methodInfoToCast;
3426+
33953427
methodInfoToCast = MakeConcreteMethodIfGeneric(methodInfoToCast, genericsTypes, inferedGenericsTypes);
33963428

33973429
bool parametersCastOK = true;
@@ -3416,7 +3448,7 @@ protected virtual MethodInfo TryToCastMethodParametersToMakeItCallable(MethodInf
34163448
&& modifiedArgs[a] is InternalDelegate)
34173449
{
34183450
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
3419-
modifiedArgs[a] = new Predicate<object>(o => (bool)(led(new object[] { o })));
3451+
modifiedArgs[a] = new Predicate<object>(o => (bool)led(new object[] { o }));
34203452
}
34213453
else if (paramTypeName.StartsWith("Func")
34223454
&& modifiedArgs[a] is InternalDelegate)
@@ -3444,6 +3476,49 @@ protected virtual MethodInfo TryToCastMethodParametersToMakeItCallable(MethodInf
34443476
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
34453477
modifiedArgs[a] = new Converter<object, object>(o => led(new object[] { o }));
34463478
}
3479+
else if(typeof(Delegate).IsAssignableFrom(parameterType)
3480+
&& modifiedArgs[a] is MethodsGroupEncaps methodsGroupEncaps)
3481+
{
3482+
MethodInfo invokeMethod = parameterType.GetMethod("Invoke");
3483+
MethodInfo methodForDelegate = Array.Find(methodsGroupEncaps.MethodsGroup, m => invokeMethod.GetParameters().Length == m.GetParameters().Length && invokeMethod.ReturnType.IsAssignableFrom(m.ReturnType));
3484+
if (methodForDelegate != null)
3485+
{
3486+
Type[] parametersTypes = methodForDelegate.GetParameters().Select(p => p.ParameterType).ToArray();
3487+
Type delegateType;
3488+
3489+
if (methodForDelegate.ReturnType == typeof(void))
3490+
{
3491+
delegateType = Type.GetType($"System.Action`{parametersTypes.Length}");
3492+
}
3493+
else if(paramTypeName.StartsWith("Predicate"))
3494+
{
3495+
delegateType = typeof(Predicate<>);
3496+
parametersTypes = parametersTypes.Concat(new Type[] { typeof(bool) }).ToArray();
3497+
}
3498+
else if (paramTypeName.StartsWith("Converter"))
3499+
{
3500+
delegateType = typeof(Converter<,>);
3501+
parametersTypes = parametersTypes.Concat(new Type[] { methodForDelegate.ReturnType }).ToArray();
3502+
}
3503+
else
3504+
{
3505+
delegateType = Type.GetType($"System.Func`{parametersTypes.Length + 1}");
3506+
parametersTypes = parametersTypes.Concat(new Type[] { methodForDelegate.ReturnType }).ToArray();
3507+
}
3508+
3509+
delegateType = delegateType.MakeGenericType(parametersTypes);
3510+
3511+
modifiedArgs[a] = Delegate.CreateDelegate(delegateType, methodsGroupEncaps.ContainerObject, methodForDelegate);
3512+
3513+
if(oldMethodInfo.IsGenericMethod &&
3514+
methodInfoToCast.GetGenericArguments().Length == parametersTypes.Length &&
3515+
!methodInfoToCast.GetGenericArguments().SequenceEqual(parametersTypes) &&
3516+
string.IsNullOrWhiteSpace(genericsTypes))
3517+
{
3518+
methodInfoToCast = MakeConcreteMethodIfGeneric(oldMethodInfo, genericsTypes, parametersTypes);
3519+
}
3520+
}
3521+
}
34473522
else
34483523
{
34493524
try
@@ -3478,7 +3553,7 @@ protected virtual MethodInfo TryToCastMethodParametersToMakeItCallable(MethodInf
34783553
{
34793554
try
34803555
{
3481-
ParameterCastEvaluationEventArg parameterCastEvaluationEventArg = new ParameterCastEvaluationEventArg(methodInfo, parameterType, modifiedArgs[a], a, this, onInstance);
3556+
ParameterCastEvaluationEventArg parameterCastEvaluationEventArg = new ParameterCastEvaluationEventArg(methodInfoToCast, parameterType, modifiedArgs[a], a, this, onInstance);
34823557

34833558
EvaluateParameterCast?.Invoke(this, parameterCastEvaluationEventArg);
34843559

@@ -4299,6 +4374,13 @@ public SubExpression(string expression)
42994374
}
43004375
}
43014376

4377+
public partial class MethodsGroupEncaps
4378+
{
4379+
public object ContainerObject { get; set; }
4380+
4381+
public MethodInfo[] MethodsGroup { get; set; }
4382+
}
4383+
43024384
public partial class BubbleExceptionContainer
43034385
{
43044386
public Exception Exception { get; set; }

0 commit comments

Comments
 (0)