Skip to content

Commit 0514161

Browse files
authored
Merge pull request #39 from codingseb/dev
Dev
2 parents 56ae71c + 7ef014e commit 0514161

File tree

3 files changed

+67
-43
lines changed

3 files changed

+67
-43
lines changed

CodingSeb.ExpressionEvaluator.Tests/ExpressionEvaluatorTests.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,10 @@ public void TypeTesting(string expression, Type type)
957957
[TestCase("new List<string>().GetType()", ExpectedResult = typeof(List<string>), Category = "new Keyword, Generics")]
958958
[TestCase("new Dictionary<string,List<int>>().GetType()", ExpectedResult = typeof(Dictionary<string, List<int>>), Category = "new Keyword, Generics")]
959959

960+
// Linq and Types inference
961+
[TestCase("new List<int>() { 1, 2, 3, 4 }.Where<int>(x => x > 2).Json", ExpectedResult = "[3,4]", Category = "Linq, Lambda, new Keyword, Generics")]
962+
[TestCase("new List<int>() { 1, 2, 3, 4 }.Where(x => x > 2).Json", ExpectedResult = "[3,4]", Category = "Linq, Type inference, Lambda, new Keyword, Generics")]
963+
960964
#endregion
961965

962966
#region Complex expressions
@@ -1967,12 +1971,9 @@ public object EvaluateWithSpecificEvaluator(ExpressionEvaluator evaluator, strin
19671971
{
19681972
return evaluator.Evaluate(expression);
19691973
}
1970-
catch (Exception exception)
1974+
catch (Exception exception) when (inCaseOfException != null)
19711975
{
1972-
if (inCaseOfException == null)
1973-
throw;
1974-
else
1975-
return inCaseOfException(exception);
1976+
return inCaseOfException(exception);
19761977
}
19771978
}
19781979

CodingSeb.ExpressionEvaluator/CodingSeb.ExpressionEvaluator.csproj

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
<Product>CodingSeb.ExpressionEvaluator</Product>
66
<Description>A Simple Math and Pseudo C# Expression Evaluator in One C# File. Can also execute small C# like scripts</Description>
77
<Copyright>Copyright © Coding Seb 2017</Copyright>
8-
<Version>1.4.1.0</Version>
9-
<AssemblyVersion>1.4.1.0</AssemblyVersion>
10-
<FileVersion>1.4.1.0</FileVersion>
8+
<Version>1.4.2.0</Version>
9+
<AssemblyVersion>1.4.2.0</AssemblyVersion>
10+
<FileVersion>1.4.2.0</FileVersion>
1111
<OutputPath>bin\$(Configuration)\</OutputPath>
1212
<Authors>Coding Seb</Authors>
1313
<PackageId>CodingSeb.ExpressionEvaluator</PackageId>
@@ -19,7 +19,11 @@
1919
<PackageIconUrl>https://github.com/codingseb/ExpressionEvaluator/blob/master/Icon.png?raw=true</PackageIconUrl>
2020
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
2121
<PackageReleaseNotes>Correction of bug :
22-
* Added a righthandOperator 'Not' does not work</PackageReleaseNotes>
22+
* In Lambda blocks did not keep options, namespaces and assemblies.
23+
24+
Improvement
25+
* Easy and optimistic generic types inference
26+
* Default assemblies (all loaded assemblies) Loaded statically (for better perfs)</PackageReleaseNotes>
2327
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
2428
</PropertyGroup>
2529
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/******************************************************************************************************
22
Title : ExpressionEvaluator (https://github.com/codingseb/ExpressionEvaluator)
3-
Version : 1.4.1.0
3+
Version : 1.4.2.0
44
(if last digit (the forth) is not a zero, the version is an intermediate version and can be unstable)
55
66
Author : Coding Seb
@@ -452,11 +452,18 @@ public static void ClearAllCaches()
452452

453453
#region Assemblies, Namespaces and types lists
454454

455+
private static IList<Assembly> staticAssemblies;
456+
private IList<Assembly> assemblies;
457+
455458
/// <summary>
456459
/// All assemblies needed to resolves Types
457460
/// by default all Assemblies loaded in the current AppDomain
458461
/// </summary>
459-
public virtual IList<Assembly> Assemblies { get; set; } = new List<Assembly>();
462+
public virtual IList<Assembly> Assemblies
463+
{
464+
get { return assemblies ?? (assemblies = staticAssemblies) ?? (assemblies = staticAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList()); }
465+
set { assemblies = value; }
466+
}
460467

461468
/// <summary>
462469
/// All Namespaces Where to find types
@@ -848,8 +855,6 @@ public IDictionary<string, object> Variables
848855
/// </summary>
849856
public ExpressionEvaluator()
850857
{
851-
AssembliesInit();
852-
853858
DefaultDecimalSeparatorInit();
854859

855860
Init();
@@ -864,11 +869,6 @@ public ExpressionEvaluator(IDictionary<string, object> variables) : this()
864869
Variables = variables;
865870
}
866871

867-
protected virtual void AssembliesInit()
868-
{
869-
Assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
870-
}
871-
872872
protected virtual void DefaultDecimalSeparatorInit()
873873
{
874874
numberRegexPattern = string.Format(numberRegexOrigPattern, @"\.", string.Empty);
@@ -1362,8 +1362,6 @@ void forAction(int index)
13621362
breakCalled = isBreak;
13631363
continueCalled = isContinue;
13641364

1365-
inScript = false;
1366-
13671365
if (isReturn || OptionOnNoReturnKeywordFoundInScriptAction == OptionOnNoReturnKeywordFoundInScriptAction.ReturnAutomaticallyLastEvaluatedExpression)
13681366
return lastResult;
13691367
else if (OptionOnNoReturnKeywordFoundInScriptAction == OptionOnNoReturnKeywordFoundInScriptAction.ReturnNull)
@@ -1419,7 +1417,7 @@ public object Evaluate(string expression)
14191417

14201418
for (int i = 0; i < expression.Length; i++)
14211419
{
1422-
if (!ParsingMethods.Any(m => m(expression, stack, ref i)))
1420+
if (!ParsingMethods.Any(parsingMethod => parsingMethod(expression, stack, ref i)))
14231421
{
14241422
string s = expression.Substring(i, 1);
14251423

@@ -1735,6 +1733,7 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
17351733
object obj = stack.Pop();
17361734
object keepObj = obj;
17371735
Type objType = null;
1736+
Type[] inferedGenericsTypes = obj.GetType().GenericTypeArguments;
17381737
ValueTypeNestingTrace valueTypeNestingTrace = null;
17391738

17401739
if (obj != null && TypesToBlock.Contains(obj.GetType()))
@@ -1775,7 +1774,7 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
17751774
throw new ExpressionEvaluatorSyntaxErrorException($"[{objType}] object has no Method named \"{varFuncName}\".");
17761775

17771776
// Standard Instance or public method find
1778-
MethodInfo methodInfo = GetRealMethod(ref objType, ref obj, varFuncName, flag, oArgs, genericsTypes);
1777+
MethodInfo methodInfo = GetRealMethod(ref objType, ref obj, varFuncName, flag, oArgs, genericsTypes, inferedGenericsTypes);
17791778

17801779
// if not found check if obj is an expandoObject or similar
17811780
if (obj is IDynamicMetaObjectProvider
@@ -1807,7 +1806,7 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
18071806
for (int e = 0; e < StaticTypesForExtensionsMethods.Count && methodInfo == null; e++)
18081807
{
18091808
Type type = StaticTypesForExtensionsMethods[e];
1810-
methodInfo = GetRealMethod(ref type, ref extentionObj, varFuncName, StaticBindingFlag, oArgs, genericsTypes);
1809+
methodInfo = GetRealMethod(ref type, ref extentionObj, varFuncName, StaticBindingFlag, oArgs, genericsTypes, inferedGenericsTypes);
18111810
isExtention = methodInfo != null;
18121811
}
18131812
}
@@ -2042,17 +2041,14 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
20422041
{
20432042
dictionaryObject[varFuncName] = varValue;
20442043
}
2044+
else if (valueTypeNestingTrace != null)
2045+
{
2046+
valueTypeNestingTrace.Value = varValue;
2047+
valueTypeNestingTrace.AssignValue();
2048+
}
20452049
else
20462050
{
2047-
if (valueTypeNestingTrace != null)
2048-
{
2049-
valueTypeNestingTrace.Value = varValue;
2050-
valueTypeNestingTrace.AssignValue();
2051-
}
2052-
else
2053-
{
2054-
((dynamic)member).SetValue(obj, varValue);
2055-
}
2051+
((dynamic)member).SetValue(obj, varValue);
20562052
}
20572053
}
20582054
}
@@ -2756,21 +2752,33 @@ protected virtual bool GetLambdaExpression(string expression, Stack<object> stac
27562752

27572753
stack.Push(new InternalDelegate((object[] args) =>
27582754
{
2759-
Dictionary<string, object> vars = new Dictionary<string, object>(Variables);
2755+
var vars = new Dictionary<string, object>(variables);
27602756

27612757
for (int a = 0; a < argsNames.Count || a < args.Length; a++)
27622758
{
27632759
vars[argsNames[a]] = args[a];
27642760
}
27652761

2766-
ExpressionEvaluator expressionEvaluator = new ExpressionEvaluator(vars);
2762+
var savedVars = variables;
2763+
Variables = vars;
27672764

27682765
string lambdaBody = lambdaExpressionMatch.Groups["expression"].Value.Trim();
27692766

2767+
object result = null;
2768+
27702769
if (inScript && lambdaBody.StartsWith("{") && lambdaBody.EndsWith("}"))
2771-
return expressionEvaluator.ScriptEvaluate(lambdaBody.Substring(1, lambdaBody.Length - 2));
2770+
{
2771+
result = ScriptEvaluate(lambdaBody.Substring(1, lambdaBody.Length - 2));
2772+
inScript = true;
2773+
}
27722774
else
2773-
return expressionEvaluator.Evaluate(lambdaExpressionMatch.Groups["expression"].Value);
2775+
{
2776+
result = Evaluate(lambdaExpressionMatch.Groups["expression"].Value);
2777+
}
2778+
2779+
variables = savedVars;
2780+
2781+
return result;
27742782
}));
27752783

27762784
return true;
@@ -2781,7 +2789,7 @@ protected virtual bool GetLambdaExpression(string expression, Stack<object> stac
27812789
}
27822790
}
27832791

2784-
protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string func, BindingFlags flag, List<object> args, string genericsTypes = "")
2792+
protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string func, BindingFlags flag, List<object> args, string genericsTypes, Type[] inferedGenericsTypes)
27852793
{
27862794
MethodInfo methodInfo = null;
27872795
List<object> modifiedArgs = new List<object>(args);
@@ -2790,7 +2798,7 @@ protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string
27902798
&& (func.StartsWith("Fluid", StringComparisonForCasing)
27912799
|| func.StartsWith("Fluent", StringComparisonForCasing)))
27922800
{
2793-
methodInfo = GetRealMethod(ref type, ref obj, func.Substring(func.StartsWith("Fluid", StringComparisonForCasing) ? 5 : 6), flag, modifiedArgs, genericsTypes);
2801+
methodInfo = GetRealMethod(ref type, ref obj, func.Substring(func.StartsWith("Fluid", StringComparisonForCasing) ? 5 : 6), flag, modifiedArgs, genericsTypes, inferedGenericsTypes);
27942802
if (methodInfo != null)
27952803
{
27962804
if (methodInfo.ReturnType == typeof(void))
@@ -2818,7 +2826,7 @@ protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string
28182826

28192827
if (methodInfo != null)
28202828
{
2821-
methodInfo = MakeConcreteMethodIfGeneric(methodInfo, genericsTypes);
2829+
methodInfo = MakeConcreteMethodIfGeneric(methodInfo, genericsTypes, inferedGenericsTypes);
28222830
}
28232831
else
28242832
{
@@ -2828,7 +2836,7 @@ protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string
28282836

28292837
for (int m = 0; m < methodInfos.Count && methodInfo == null; m++)
28302838
{
2831-
methodInfos[m] = MakeConcreteMethodIfGeneric(methodInfos[m], genericsTypes);
2839+
methodInfos[m] = MakeConcreteMethodIfGeneric(methodInfos[m], genericsTypes, inferedGenericsTypes);
28322840

28332841
bool parametersCastOK = true;
28342842

@@ -2891,14 +2899,25 @@ protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string
28912899
return methodInfo;
28922900
}
28932901

2894-
protected virtual MethodInfo MakeConcreteMethodIfGeneric(MethodInfo methodInfo, string genericsTypes = "")
2902+
protected virtual MethodInfo MakeConcreteMethodIfGeneric(MethodInfo methodInfo, string genericsTypes, Type[] inferedGenericsTypes)
28952903
{
28962904
if (methodInfo.IsGenericMethod)
28972905
{
28982906
if (genericsTypes.Equals(string.Empty))
2899-
return methodInfo.MakeGenericMethod(Enumerable.Repeat(typeof(object), methodInfo.GetGenericArguments().Length).ToArray());
2907+
{
2908+
if(inferedGenericsTypes != null && inferedGenericsTypes.Length == methodInfo.GetGenericArguments().Length)
2909+
{
2910+
return methodInfo.MakeGenericMethod(inferedGenericsTypes);
2911+
}
2912+
else
2913+
{
2914+
return methodInfo.MakeGenericMethod(Enumerable.Repeat(typeof(object), methodInfo.GetGenericArguments().Length).ToArray());
2915+
}
2916+
}
29002917
else
2918+
{
29012919
return methodInfo.MakeGenericMethod(GetConcreteTypes(genericsTypes));
2920+
}
29022921
}
29032922

29042923
return methodInfo;
@@ -3135,7 +3154,7 @@ protected virtual Type GetTypeByFriendlyName(string typeName, string genericType
31353154

31363155
if (result == null)
31373156
{
3138-
result = Types.ToList().Find(type => type.Name.Equals(typeName, StringComparisonForCasing));
3157+
result = Types.ToList().Find(type => type.Name.Equals(typeName, StringComparisonForCasing) || type.FullName.StartsWith(typeName + ","));
31393158
}
31403159

31413160
for (int a = 0; a < Assemblies.Count && result == null; a++)

0 commit comments

Comments
 (0)