Skip to content

Commit a4944c3

Browse files
committed
First Correction for #65 Correction for Enumerable (extensions with a lambda (Sum, Average, Min, Max)
1 parent 366e2f3 commit a4944c3

File tree

3 files changed

+141
-57
lines changed

3 files changed

+141
-57
lines changed

CodingSeb.ExpressionEvaluator.Tests/ExpressionEvaluatorTests.cs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,7 +1874,7 @@ void Evaluator_PreEvaluateVariable(object sender, VariablePreEvaluationEventArg
18741874

18751875
#endregion
18761876

1877-
#region inherits ExpressionEvaluator
1877+
#region Inherits ExpressionEvaluator
18781878

18791879
#region Redefine existing operators
18801880

@@ -2082,14 +2082,44 @@ void Evaluator_PreEvaluateVariable(object sender, VariablePreEvaluationEventArg
20822082

20832083
#endregion
20842084

2085-
#region bug resolution
2085+
#region Bug resolution
20862086

20872087
yield return new TestCaseData(new ExpressionEvaluator()
20882088
, "(new List<Regex>()).GetType()"
20892089
, null)
20902090
.Returns(typeof(List<Regex>))
20912091
.SetCategory("Bug resolution");
20922092

2093+
// For bug #65
2094+
var Persons = new List<Person2>() { new Person2() { Code = "QT00010", Name = "Pedrito", Number = 11.11m },
2095+
new Person2() { Code = "QT00011", Name = "Pablito", Number = 12.11m }};
2096+
2097+
yield return new TestCaseData(new ExpressionEvaluator() { Context = new { Persons } }
2098+
, "Persons.Sum(x=>x.Number)"
2099+
, null)
2100+
.Returns(23.22m)
2101+
.SetCategory("Bug resolution");
2102+
2103+
yield return new TestCaseData(new ExpressionEvaluator() { Context = new { Persons } }
2104+
, "Persons.Average(x=>x.Number)"
2105+
, null)
2106+
.Returns(11.61m)
2107+
.SetCategory("Bug resolution");
2108+
2109+
yield return new TestCaseData(new ExpressionEvaluator() { Context = new { Persons } }
2110+
, "Persons.Max(x=>x.Number)"
2111+
, null)
2112+
.Returns(12.11m)
2113+
.SetCategory("Bug resolution");
2114+
2115+
yield return new TestCaseData(new ExpressionEvaluator() { Context = new { Persons } }
2116+
, "Persons.Min(x=>x.Number)"
2117+
, null)
2118+
.Returns(11.11m)
2119+
.SetCategory("Bug resolution");
2120+
2121+
// end of bug #65
2122+
20932123
#endregion
20942124
}
20952125
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace CodingSeb.ExpressionEvaluator.Tests
2+
{
3+
/// <summary>
4+
/// class to test specific bug #65 (When multiple implementation of method with lambda argument)
5+
/// </summary>
6+
public class Person2
7+
{
8+
public string Code { get; set; }
9+
public string Name { get; set; }
10+
public decimal Number { get; set; }
11+
}
12+
}

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 97 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3103,69 +3103,44 @@ protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string
31033103
.Where(m => m.Name.Equals(func, StringComparisonForCasing) && m.GetParameters().Length == modifiedArgs.Count)
31043104
.ToList();
31053105

3106-
for (int m = 0; m < methodInfos.Count && methodInfo == null; m++)
3106+
// For Linq methods that are overloaded and implement possibly lambda arguments
3107+
try
31073108
{
3108-
methodInfos[m] = MakeConcreteMethodIfGeneric(methodInfos[m], genericsTypes, inferedGenericsTypes);
3109-
3110-
bool parametersCastOK = true;
3111-
3112-
modifiedArgs = new List<object>(args);
3113-
3114-
for (int a = 0; a < modifiedArgs.Count; a++)
3109+
if (methodInfos.Count > 1
3110+
&& type == typeof(Enumerable)
3111+
&& args.Count == 2
3112+
&& args[1] is InternalDelegate internalDelegate
3113+
&& args[0] is IEnumerable enumerable
3114+
&& enumerable.GetEnumerator() is IEnumerator enumerator
3115+
&& enumerator.MoveNext()
3116+
&& methodInfos.Any(m => m.GetParameters().Any(p => p.ParameterType.Name.StartsWith("Func"))))
31153117
{
3116-
Type parameterType = methodInfos[m].GetParameters()[a].ParameterType;
3117-
string paramTypeName = parameterType.Name;
3118+
Type lambdaResultType = internalDelegate.Invoke(enumerator.Current).GetType();
31183119

3119-
if (paramTypeName.StartsWith("Predicate")
3120-
&& modifiedArgs[a] is InternalDelegate)
3121-
{
3122-
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
3123-
modifiedArgs[a] = new Predicate<object>(o => (bool)(led(new object[] { o })));
3124-
}
3125-
else if (paramTypeName.StartsWith("Func")
3126-
&& modifiedArgs[a] is InternalDelegate)
3120+
methodInfo = methodInfos.Find(m =>
31273121
{
3128-
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
3129-
DelegateEncaps de = new DelegateEncaps(led);
3130-
MethodInfo encapsMethod = de.GetType()
3131-
.GetMethod($"Func{parameterType.GetGenericArguments().Length - 1}")
3132-
.MakeGenericMethod(parameterType.GetGenericArguments());
3133-
modifiedArgs[a] = Delegate.CreateDelegate(parameterType, de, encapsMethod);
3134-
}
3135-
else if (paramTypeName.StartsWith("Action")
3136-
&& modifiedArgs[a] is InternalDelegate)
3137-
{
3138-
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
3139-
DelegateEncaps de = new DelegateEncaps(led);
3140-
MethodInfo encapsMethod = de.GetType()
3141-
.GetMethod($"Action{parameterType.GetGenericArguments().Length}")
3142-
.MakeGenericMethod(parameterType.GetGenericArguments());
3143-
modifiedArgs[a] = Delegate.CreateDelegate(parameterType, de, encapsMethod);
3144-
}
3145-
else if (paramTypeName.StartsWith("Converter")
3146-
&& modifiedArgs[a] is InternalDelegate)
3122+
ParameterInfo[] parameterInfos = m.GetParameters();
3123+
3124+
return parameterInfos.Length == 2
3125+
&& parameterInfos[1].ParameterType.Name.StartsWith("Func")
3126+
&& parameterInfos[1].ParameterType.GenericTypeArguments is Type[] genericTypesArgs
3127+
&& genericTypesArgs.Length == 2
3128+
&& genericTypesArgs[1] == lambdaResultType;
3129+
});
3130+
3131+
if (methodInfo != null)
31473132
{
3148-
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
3149-
modifiedArgs[a] = new Converter<object, object>(o => led(new object[] { o }));
3150-
}
3151-
else
3152-
{
3153-
try
3154-
{
3155-
if (!methodInfos[m].GetParameters()[a].ParameterType.IsAssignableFrom(modifiedArgs[a].GetType()))
3156-
{
3157-
modifiedArgs[a] = Convert.ChangeType(modifiedArgs[a], methodInfos[m].GetParameters()[a].ParameterType);
3158-
}
3159-
}
3160-
catch
3161-
{
3162-
parametersCastOK = false;
3163-
}
3133+
methodInfo = TryToCastMethodParametersToMakeItCallable(methodInfo, modifiedArgs, genericsTypes, inferedGenericsTypes);
31643134
}
31653135
}
3136+
}
3137+
catch { }
31663138

3167-
if (parametersCastOK)
3168-
methodInfo = methodInfos[m];
3139+
for (int m = 0; m < methodInfos.Count && methodInfo == null; m++)
3140+
{
3141+
modifiedArgs = new List<object>(args);
3142+
3143+
methodInfo = TryToCastMethodParametersToMakeItCallable(methodInfos[m], modifiedArgs, genericsTypes, inferedGenericsTypes);
31693144
}
31703145

31713146
if (methodInfo != null)
@@ -3178,6 +3153,73 @@ protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string
31783153
return methodInfo;
31793154
}
31803155

3156+
protected virtual MethodInfo TryToCastMethodParametersToMakeItCallable(MethodInfo methodInfoToCast, List<object> modifiedArgs, string genericsTypes, Type[] inferedGenericsTypes)
3157+
{
3158+
MethodInfo methodInfo = null;
3159+
3160+
methodInfoToCast = MakeConcreteMethodIfGeneric(methodInfoToCast, genericsTypes, inferedGenericsTypes);
3161+
3162+
bool parametersCastOK = true;
3163+
3164+
for (int a = 0; a < modifiedArgs.Count; a++)
3165+
{
3166+
Type parameterType = methodInfoToCast.GetParameters()[a].ParameterType;
3167+
string paramTypeName = parameterType.Name;
3168+
3169+
if (paramTypeName.StartsWith("Predicate")
3170+
&& modifiedArgs[a] is InternalDelegate)
3171+
{
3172+
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
3173+
modifiedArgs[a] = new Predicate<object>(o => (bool)(led(new object[] { o })));
3174+
}
3175+
else if (paramTypeName.StartsWith("Func")
3176+
&& modifiedArgs[a] is InternalDelegate)
3177+
{
3178+
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
3179+
DelegateEncaps de = new DelegateEncaps(led);
3180+
MethodInfo encapsMethod = de.GetType()
3181+
.GetMethod($"Func{parameterType.GetGenericArguments().Length - 1}")
3182+
.MakeGenericMethod(parameterType.GetGenericArguments());
3183+
modifiedArgs[a] = Delegate.CreateDelegate(parameterType, de, encapsMethod);
3184+
}
3185+
else if (paramTypeName.StartsWith("Action")
3186+
&& modifiedArgs[a] is InternalDelegate)
3187+
{
3188+
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
3189+
DelegateEncaps de = new DelegateEncaps(led);
3190+
MethodInfo encapsMethod = de.GetType()
3191+
.GetMethod($"Action{parameterType.GetGenericArguments().Length}")
3192+
.MakeGenericMethod(parameterType.GetGenericArguments());
3193+
modifiedArgs[a] = Delegate.CreateDelegate(parameterType, de, encapsMethod);
3194+
}
3195+
else if (paramTypeName.StartsWith("Converter")
3196+
&& modifiedArgs[a] is InternalDelegate)
3197+
{
3198+
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
3199+
modifiedArgs[a] = new Converter<object, object>(o => led(new object[] { o }));
3200+
}
3201+
else
3202+
{
3203+
try
3204+
{
3205+
if (!methodInfoToCast.GetParameters()[a].ParameterType.IsAssignableFrom(modifiedArgs[a].GetType()))
3206+
{
3207+
modifiedArgs[a] = Convert.ChangeType(modifiedArgs[a], methodInfoToCast.GetParameters()[a].ParameterType);
3208+
}
3209+
}
3210+
catch
3211+
{
3212+
parametersCastOK = false;
3213+
}
3214+
}
3215+
}
3216+
3217+
if (parametersCastOK)
3218+
methodInfo = methodInfoToCast;
3219+
3220+
return methodInfo;
3221+
}
3222+
31813223
protected virtual MethodInfo MakeConcreteMethodIfGeneric(MethodInfo methodInfo, string genericsTypes, Type[] inferedGenericsTypes)
31823224
{
31833225
if (methodInfo.IsGenericMethod)

0 commit comments

Comments
 (0)