Skip to content

Commit 48abbe4

Browse files
committed
FIX #68 Array.Contains not working
1 parent e58de49 commit 48abbe4

File tree

5 files changed

+69
-93
lines changed

5 files changed

+69
-93
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Source code and symbols (.pdb files) for debugging are available on [Symbol Sour
4848
- Can generate delegates or lambda expression
4949
- Full suite of unit tests
5050
- Good performance compared to other similar projects
51-
- Partial support of generic, params array and extension methods
51+
- Partial support of generic, params array and extension methods (only with implicit generic arguments detection)
5252
- Partial support of `dynamic` (`ExpandoObject` for get properties and method invocation, see #72)
5353
- Case insensitive expressions (default is case sensitive)
5454
- Ability to discover identifiers (variables, types, parameters) of a given expression

src/DynamicExpresso.Core/DynamicExpresso.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<PackageLicenseUrl>https://github.com/davideicardi/DynamicExpresso#license</PackageLicenseUrl>
1717
<RepositoryUrl>https://github.com/davideicardi/DynamicExpresso.git</RepositoryUrl>
1818
<RepositoryType>git</RepositoryType>
19-
<VersionPrefix>2.0.1</VersionPrefix>
19+
<VersionPrefix>2.0.2</VersionPrefix>
2020
<VersionSuffix></VersionSuffix>
2121
</PropertyGroup>
2222

src/DynamicExpresso.Core/Parsing/Parser.cs

Lines changed: 32 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,31 +1262,23 @@ private static void AddInterface(List<Type> types, Type type)
12621262
}
12631263
}
12641264

1265-
private class MethodData
1266-
{
1267-
public MethodBase MethodBase;
1268-
public ParameterInfo[] Parameters;
1269-
public Expression[] PromotedParameters;
1270-
public bool HasParamsArray;
1271-
}
1272-
1273-
private MethodData[] FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args)
1265+
private static MethodData[] FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args)
12741266
{
12751267
var applicable = methods.
12761268
Select(m => new MethodData { MethodBase = m, Parameters = m.GetParameters() }).
12771269
Where(m => CheckIfMethodIsApplicableAndPrepareIt(m, args)).
12781270
ToArray();
12791271
if (applicable.Length > 1)
12801272
{
1281-
applicable = applicable.
1273+
return applicable.
12821274
Where(m => applicable.All(n => m == n || MethodHasPriority(args, m, n))).
12831275
ToArray();
12841276
}
12851277

12861278
return applicable;
12871279
}
12881280

1289-
private bool CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Expression[] args)
1281+
private static bool CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Expression[] args)
12901282
{
12911283
if (method.Parameters.Length > args.Length)
12921284
return false;
@@ -1374,41 +1366,48 @@ private bool CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Expression
13741366
{
13751367
var methodInfo = (MethodInfo)method.MethodBase;
13761368

1377-
var genericArgsType = ExtractActualGenericArguments(
1378-
method.Parameters.Select(p => p.ParameterType).ToArray(),
1379-
method.PromotedParameters.Select(p => p.Type).ToArray());
1369+
var actualGenericArgs = ExtractActualGenericArguments(
1370+
method.Parameters.Select(p => p.ParameterType).ToArray(),
1371+
method.PromotedParameters.Select(p => p.Type).ToArray());
13801372

1381-
method.MethodBase = methodInfo.MakeGenericMethod(genericArgsType.ToArray());
1373+
var genericArgs = methodInfo.GetGenericArguments()
1374+
.Select(p => actualGenericArgs[p.Name])
1375+
.ToArray();
1376+
1377+
method.MethodBase = methodInfo.MakeGenericMethod(genericArgs);
13821378
}
13831379

13841380
return true;
13851381
}
13861382

1387-
private List<Type> ExtractActualGenericArguments(Type[] requestedParameters, Type[] actualParameters)
1383+
private static Dictionary<string, Type> ExtractActualGenericArguments(
1384+
Type[] methodGenericParameters,
1385+
Type[] methodActualParameters)
13881386
{
1389-
var extractedGenericTypes = new List<Type>();
1387+
var extractedGenericTypes = new Dictionary<string, Type>();
13901388

1391-
for (var i = 0; i < requestedParameters.Length; i++)
1389+
for (var i = 0; i < methodGenericParameters.Length; i++)
13921390
{
1393-
var requestedType = requestedParameters[i];
1394-
var actualType = actualParameters[i];
1391+
var requestedType = methodGenericParameters[i];
1392+
var actualType = methodActualParameters[i];
13951393

13961394
if (requestedType.IsGenericParameter)
13971395
{
1398-
extractedGenericTypes.Add(actualType);
1396+
extractedGenericTypes[requestedType.Name] = actualType;
13991397
}
14001398
else if (requestedType.ContainsGenericParameters)
14011399
{
14021400
var innerGenericTypes = ExtractActualGenericArguments(requestedType.GetGenericArguments(), actualType.GetGenericArguments());
14031401

1404-
extractedGenericTypes.AddRange(innerGenericTypes);
1402+
foreach (var innerGenericType in innerGenericTypes)
1403+
extractedGenericTypes[innerGenericType.Key] = innerGenericType.Value;
14051404
}
14061405
}
14071406

14081407
return extractedGenericTypes;
14091408
}
14101409

1411-
private Expression PromoteExpression(Expression expr, Type type, bool exact)
1410+
private static Expression PromoteExpression(Expression expr, Type type, bool exact)
14121411
{
14131412
if (expr.Type == type) return expr;
14141413
if (expr is ConstantExpression)
@@ -1440,70 +1439,6 @@ private Expression PromoteExpression(Expression expr, Type type, bool exact)
14401439
return null;
14411440
}
14421441

1443-
//object ParseNumber(string text, Type type)
1444-
//{
1445-
// switch (Type.GetTypeCode(GetNonNullableType(type)))
1446-
// {
1447-
// case TypeCode.SByte:
1448-
// sbyte sb;
1449-
// if (sbyte.TryParse(text, ParseLiteralNumberStyle, ParseCulture, out sb)) return sb;
1450-
// break;
1451-
// case TypeCode.Byte:
1452-
// byte b;
1453-
// if (byte.TryParse(text, ParseLiteralNumberStyle, ParseCulture, out b)) return b;
1454-
// break;
1455-
// case TypeCode.Int16:
1456-
// short s;
1457-
// if (short.TryParse(text, ParseLiteralNumberStyle, ParseCulture, out s)) return s;
1458-
// break;
1459-
// case TypeCode.UInt16:
1460-
// ushort us;
1461-
// if (ushort.TryParse(text, ParseLiteralUnsignedNumberStyle, ParseCulture, out us)) return us;
1462-
// break;
1463-
// case TypeCode.Int32:
1464-
// int i;
1465-
// if (int.TryParse(text, ParseLiteralNumberStyle, ParseCulture, out i)) return i;
1466-
// break;
1467-
// case TypeCode.UInt32:
1468-
// uint ui;
1469-
// if (uint.TryParse(text, ParseLiteralUnsignedNumberStyle, ParseCulture, out ui)) return ui;
1470-
// break;
1471-
// case TypeCode.Int64:
1472-
// long l;
1473-
// if (long.TryParse(text, ParseLiteralNumberStyle, ParseCulture, out l)) return l;
1474-
// break;
1475-
// case TypeCode.UInt64:
1476-
// ulong ul;
1477-
// if (ulong.TryParse(text, ParseLiteralUnsignedNumberStyle, ParseCulture, out ul)) return ul;
1478-
// break;
1479-
// case TypeCode.Single:
1480-
// float f;
1481-
// if (float.TryParse(text, ParseLiteralDecimalNumberStyle, ParseCulture, out f)) return f;
1482-
// break;
1483-
// case TypeCode.Double:
1484-
// double d;
1485-
// if (double.TryParse(text, ParseLiteralDecimalNumberStyle, ParseCulture, out d)) return d;
1486-
// break;
1487-
// case TypeCode.Decimal:
1488-
// decimal e;
1489-
// if (decimal.TryParse(text, ParseLiteralDecimalNumberStyle, ParseCulture, out e)) return e;
1490-
// break;
1491-
// }
1492-
// return null;
1493-
//}
1494-
1495-
//static object ParseEnum(string name, Type type)
1496-
//{
1497-
// if (type.IsEnum)
1498-
// {
1499-
// MemberInfo[] memberInfos = type.FindMembers(MemberTypes.Field,
1500-
// BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static,
1501-
// Type.FilterNameIgnoreCase, name);
1502-
// if (memberInfos.Length != 0) return ((FieldInfo)memberInfos[0]).GetValue(null);
1503-
// }
1504-
// return null;
1505-
//}
1506-
15071442
private static bool IsCompatibleWith(Type source, Type target)
15081443
{
15091444
if (source == target)
@@ -2113,7 +2048,7 @@ private void NextToken()
21132048
private string GetIdentifier()
21142049
{
21152050
ValidateToken(TokenId.Identifier, ErrorMessages.IdentifierExpected);
2116-
string id = _token.text;
2051+
var id = _token.text;
21172052
if (id.Length > 1 && id[0] == '@')
21182053
id = id.Substring(1);
21192054
return id;
@@ -2139,9 +2074,17 @@ private void ValidateToken(TokenId t)
21392074
throw CreateParseException(_token.pos, ErrorMessages.SyntaxError);
21402075
}
21412076

2142-
private Exception CreateParseException(int pos, string format, params object[] args)
2077+
private static Exception CreateParseException(int pos, string format, params object[] args)
21432078
{
21442079
return new ParseException(string.Format(format, args), pos);
21452080
}
2081+
2082+
private class MethodData
2083+
{
2084+
public MethodBase MethodBase;
2085+
public ParameterInfo[] Parameters;
2086+
public Expression[] PromotedParameters;
2087+
public bool HasParamsArray;
2088+
}
21462089
}
21472090
}

test/DynamicExpresso.UnitTest/ExtensionsMethodsTest.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ public void Invoke_generic_parameter_extension_method()
4545
Assert.AreEqual(x.GenericParamHello(), target.Eval("x.GenericParamHello()"));
4646
}
4747

48+
[Test]
49+
public void Invoke_generic_parameter_extension_method_with_2_parameters()
50+
{
51+
var x = new MyClass[0];
52+
53+
var target = new Interpreter()
54+
.Reference(typeof(TestExtensionsMethods))
55+
.Reference(typeof(MyClass))
56+
.SetVariable("x", x);
57+
58+
Assert.AreEqual(x.GenericWith2Params(new MyClass()), target.Eval("x.GenericWith2Params(new MyClass())"));
59+
}
60+
4861
[Test]
4962
public void Invoke_generic_with_2_parameters_and_output_extension_method()
5063
{
@@ -55,7 +68,7 @@ public void Invoke_generic_with_2_parameters_and_output_extension_method()
5568
.Reference(typeof(TestExtensionsMethods))
5669
.SetVariable("x", x);
5770

58-
Assert.AreEqual(x.GenericWith2Params(), target.Eval("x.GenericWith2Params()"));
71+
Assert.AreEqual(x.GenericWith2Args(), target.Eval("x.GenericWith2Args()"));
5972
}
6073

6174
[Test]
@@ -99,13 +112,19 @@ public static string GenericParamHello<T>(this IEnumerable<T> test)
99112
return "Hello with generic param!";
100113
}
101114

115+
public static string GenericWith2Params<T>(this IEnumerable<T> test, T another)
116+
where T : ExtensionsMethodsTest.MyClass
117+
{
118+
return "Hello with 2 generic param!";
119+
}
120+
102121
public static string GenericMixedParamHello<T>(this IDictionary<string, T> test)
103122
where T : ExtensionsMethodsTest.MyClass
104123
{
105124
return "Hello with generic param!";
106125
}
107126

108-
public static T2 GenericWith2Params<T1, T2>(this IDictionary<T1, T2> test)
127+
public static T2 GenericWith2Args<T1, T2>(this IDictionary<T1, T2> test)
109128
where T2 : ExtensionsMethodsTest.MyClass
110129
{
111130
return test.First().Value;

test/DynamicExpresso.UnitTest/GithubIssues.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using NUnit.Framework;
33
using System.Collections.Generic;
4+
using System.Linq;
45
// ReSharper disable SpecifyACultureInStringConversionExplicitly
56

67
namespace DynamicExpresso.UnitTest
@@ -28,5 +29,18 @@ public void GitHub_Issue_43()
2829
Assert.AreEqual((.1).ToString(), interpreter.Eval(".1.ToString()"));
2930
Assert.AreEqual((-1-.1-0.1).ToString(), interpreter.Eval("(-1-.1-0.1).ToString()"));
3031
}
32+
33+
[Test]
34+
public void GitHub_Issue_68()
35+
{
36+
var interpreter = new Interpreter();
37+
38+
var array = new[] { 5, 10, 6 };
39+
40+
interpreter.SetVariable("array", array);
41+
42+
Assert.AreEqual(array.Contains(5), interpreter.Eval("array.Contains(5)"));
43+
Assert.AreEqual(array.Contains(3), interpreter.Eval("array.Contains(3)"));
44+
}
3145
}
3246
}

0 commit comments

Comments
 (0)