Skip to content

Commit 7f6e2e2

Browse files
committed
simples generics for methods evaluation with <>
1 parent 273f070 commit 7f6e2e2

File tree

2 files changed

+30
-10
lines changed

2 files changed

+30
-10
lines changed

CodingSeb.ExpressionEvaluator.Tests/ExpressionEvaluatorTests.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,12 @@ public void TypeTesting(string expression, Type type)
859859

860860
#endregion
861861

862+
#region Generic types Management
863+
864+
[TestCase("List(\"Hello\", \"Test\").Cast<string>().ToList<string>().GetType()", ExpectedResult = typeof(List<string>) , Category = "List function, Generics")]
865+
866+
#endregion
867+
862868
#region Complex expressions
863869
[TestCase("Enumerable.Range(1,4).Cast().Sum(x =>(int)x)", ExpectedResult = 10, Category = "Complex expression,Static method,Instance method,Lambda function,Cast")]
864870
[TestCase("System.Linq.Enumerable.Range(1,4).Cast().Sum(x =>(int)x)", ExpectedResult = 10, Category = "Complex expression,Static method,Instance method,Lambda function,Cast")]

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/******************************************************************************************************
22
Title : ExpressionEvaluator (https://github.com/codingseb/ExpressionEvaluator)
3-
Version : 1.3.2.1
4-
(if last digit is not a zero, the version is an intermediate version and can be unstable)
3+
Version : 1.3.2.2
4+
(if last digit (the forth) is not a zero, the version is an intermediate version and can be unstable)
55
66
Author : Coding Seb
77
Licence : MIT (https://github.com/codingseb/ExpressionEvaluator/blob/master/LICENSE.md)
@@ -35,6 +35,7 @@ public class ExpressionEvaluator
3535
private static readonly Regex internalCharRegex = new Regex(@"^['](\\[']|[^'])*[']");
3636
private static readonly Regex indexingBeginningRegex = new Regex(@"^[?]?\[");
3737
private static readonly Regex assignationOrPostFixOperatorRegex = new Regex(@"^\s*((?<assignmentPrefix>[+\-*/%&|^]|<<|>>)?=(?![=>])|(?<postfixOperator>([+][+]|--)(?![" + diactiticsKeywordsRegexPattern + @"0-9])))");
38+
private static readonly Regex genericsDecodeRegex = new Regex("[^,<>]+(?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?", RegexOptions.Compiled);
3839

3940
private static readonly Regex endOfStringWithDollar = new Regex("^([^\"{\\\\]|\\\\[\\\\\"0abfnrtv])*[\"{]");
4041
private static readonly Regex endOfStringWithoutDollar = new Regex("^([^\"\\\\]|\\\\[\\\\\"0abfnrtv])*[\"]");
@@ -1463,6 +1464,7 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
14631464
&& !operatorsDictionary.ContainsKey(varFuncMatch.Value.Trim()))
14641465
{
14651466
string varFuncName = varFuncMatch.Groups["name"].Value;
1467+
string genericsTypes = varFuncMatch.Groups["isgeneric"].Value;
14661468

14671469
i += varFuncMatch.Length;
14681470

@@ -1514,7 +1516,7 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
15141516
throw new ExpressionEvaluatorSyntaxErrorException($"[{objType.ToString()}] object has no Method named \"{varFuncName}\".");
15151517

15161518
// Standard Instance or public method find
1517-
MethodInfo methodInfo = GetRealMethod(ref objType, ref obj, varFuncName, flag, oArgs);
1519+
MethodInfo methodInfo = GetRealMethod(ref objType, ref obj, varFuncName, flag, oArgs, genericsTypes);
15181520

15191521
// if not found check if obj is an expandoObject or similar
15201522
if (obj is IDynamicMetaObjectProvider && obj is IDictionary<string, object> dictionaryObject && (dictionaryObject[varFuncName] is InternalDelegate || dictionaryObject[varFuncName] is Delegate))
@@ -1540,7 +1542,7 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
15401542
for (int e = 0; e < StaticTypesForExtensionsMethods.Count && methodInfo == null; e++)
15411543
{
15421544
Type type = StaticTypesForExtensionsMethods[e];
1543-
methodInfo = GetRealMethod(ref type, ref obj, varFuncName, StaticBindingFlag, oArgs);
1545+
methodInfo = GetRealMethod(ref type, ref obj, varFuncName, StaticBindingFlag, oArgs, genericsTypes);
15441546
}
15451547
}
15461548

@@ -2353,7 +2355,7 @@ private bool GetLambdaExpression(string expr, Stack<object> stack)
23532355
}
23542356
}
23552357

2356-
private MethodInfo GetRealMethod(ref Type type, ref object obj, string func, BindingFlags flag, List<object> args)
2358+
private MethodInfo GetRealMethod(ref Type type, ref object obj, string func, BindingFlags flag, List<object> args, string genericsTypes = "")
23572359
{
23582360
MethodInfo methodInfo = null;
23592361
List<object> modifiedArgs = new List<object>(args);
@@ -2362,7 +2364,7 @@ private MethodInfo GetRealMethod(ref Type type, ref object obj, string func, Bin
23622364
(func.ManageCasing(OptionCaseSensitiveEvaluationActive).StartsWith("Fluid".ManageCasing(OptionCaseSensitiveEvaluationActive))
23632365
|| func.ManageCasing(OptionCaseSensitiveEvaluationActive).StartsWith("Fluent".ManageCasing(OptionCaseSensitiveEvaluationActive))))
23642366
{
2365-
methodInfo = GetRealMethod(ref type, ref obj, func.ManageCasing(OptionCaseSensitiveEvaluationActive).Substring(func.ManageCasing(OptionCaseSensitiveEvaluationActive).StartsWith("Fluid".ManageCasing(OptionCaseSensitiveEvaluationActive)) ? 5 : 6), flag, modifiedArgs);
2367+
methodInfo = GetRealMethod(ref type, ref obj, func.ManageCasing(OptionCaseSensitiveEvaluationActive).Substring(func.ManageCasing(OptionCaseSensitiveEvaluationActive).StartsWith("Fluid".ManageCasing(OptionCaseSensitiveEvaluationActive)) ? 5 : 6), flag, modifiedArgs, genericsTypes);
23662368
if (methodInfo != null)
23672369
{
23682370
if (methodInfo.ReturnType == typeof(void))
@@ -2390,7 +2392,7 @@ private MethodInfo GetRealMethod(ref Type type, ref object obj, string func, Bin
23902392

23912393
if (methodInfo != null)
23922394
{
2393-
methodInfo = MakeConcreteMethodIfGeneric(methodInfo);
2395+
methodInfo = MakeConcreteMethodIfGeneric(methodInfo, genericsTypes);
23942396
}
23952397
else
23962398
{
@@ -2400,7 +2402,7 @@ private MethodInfo GetRealMethod(ref Type type, ref object obj, string func, Bin
24002402

24012403
for (int m = 0; m < methodInfos.Count && methodInfo == null; m++)
24022404
{
2403-
methodInfos[m] = MakeConcreteMethodIfGeneric(methodInfos[m]);
2405+
methodInfos[m] = MakeConcreteMethodIfGeneric(methodInfos[m], genericsTypes);
24042406

24052407
bool parametersCastOK = true;
24062408

@@ -2463,16 +2465,28 @@ private MethodInfo GetRealMethod(ref Type type, ref object obj, string func, Bin
24632465
return methodInfo;
24642466
}
24652467

2466-
private MethodInfo MakeConcreteMethodIfGeneric(MethodInfo methodInfo)
2468+
private MethodInfo MakeConcreteMethodIfGeneric(MethodInfo methodInfo, string genericsTypes = "")
24672469
{
24682470
if (methodInfo.IsGenericMethod)
24692471
{
2470-
return methodInfo.MakeGenericMethod(Enumerable.Repeat(typeof(object), methodInfo.GetGenericArguments().Count()).ToArray());
2472+
if (genericsTypes.Equals(string.Empty))
2473+
return methodInfo.MakeGenericMethod(Enumerable.Repeat(typeof(object), methodInfo.GetGenericArguments().Count()).ToArray());
2474+
else
2475+
return methodInfo.MakeGenericMethod(GetConcreteTypes(genericsTypes));
24712476
}
24722477

24732478
return methodInfo;
24742479
}
24752480

2481+
private Type[] GetConcreteTypes(string genericsTypes)
2482+
{
2483+
return genericsDecodeRegex
2484+
.Matches(genericsTypes.TrimStart(' ', '<').TrimEnd(' ', '>'))
2485+
.Cast<Match>()
2486+
.Select(match => GetTypeByFriendlyName(match.Value))
2487+
.ToArray();
2488+
}
2489+
24762490
private BindingFlags DetermineInstanceOrStatic(ref Type objType, ref object obj)
24772491
{
24782492
if (obj is ClassOrTypeName classOrTypeName)

0 commit comments

Comments
 (0)