Skip to content

Commit ed90b13

Browse files
authored
Fix Enum (#514)
1 parent 2c49cb0 commit ed90b13

File tree

4 files changed

+255
-30
lines changed

4 files changed

+255
-30
lines changed

src/System.Linq.Dynamic.Core/CustomTypeProviders/DefaultDynamicLinqCustomTypeProvider.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public DefaultDynamicLinqCustomTypeProvider(bool cacheCustomTypes = true)
3131
_cacheCustomTypes = cacheCustomTypes;
3232
}
3333

34-
/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.GetCustomTypes"/>
34+
/// <inheritdoc cref="IDynamicLinqCustomTypeProvider.GetCustomTypes"/>
3535
public virtual HashSet<Type> GetCustomTypes()
3636
{
3737
if (_cacheCustomTypes)
@@ -47,7 +47,7 @@ public virtual HashSet<Type> GetCustomTypes()
4747
return GetCustomTypesInternal();
4848
}
4949

50-
/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.GetExtensionMethods"/>
50+
/// <inheritdoc cref="IDynamicLinqCustomTypeProvider.GetExtensionMethods"/>
5151
public Dictionary<Type, List<MethodInfo>> GetExtensionMethods()
5252
{
5353
if (_cacheCustomTypes)
@@ -63,7 +63,7 @@ public Dictionary<Type, List<MethodInfo>> GetExtensionMethods()
6363
return GetExtensionMethodsInternal();
6464
}
6565

66-
/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.ResolveType"/>
66+
/// <inheritdoc cref="IDynamicLinqCustomTypeProvider.ResolveType"/>
6767
public Type ResolveType(string typeName)
6868
{
6969
Check.NotEmpty(typeName, nameof(typeName));
@@ -72,7 +72,7 @@ public Type ResolveType(string typeName)
7272
return ResolveType(assemblies, typeName);
7373
}
7474

75-
/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.ResolveTypeBySimpleName"/>
75+
/// <inheritdoc cref="IDynamicLinqCustomTypeProvider.ResolveTypeBySimpleName"/>
7676
public Type ResolveTypeBySimpleName(string simpleTypeName)
7777
{
7878
Check.NotEmpty(simpleTypeName, nameof(simpleTypeName));
@@ -91,7 +91,7 @@ private Dictionary<Type, List<MethodInfo>> GetExtensionMethodsInternal()
9191
{
9292
var types = GetCustomTypes();
9393

94-
List<Tuple<Type, MethodInfo>> list= new List<Tuple<Type, MethodInfo>>();
94+
List<Tuple<Type, MethodInfo>> list = new List<Tuple<Type, MethodInfo>>();
9595

9696
foreach (var type in types)
9797
{

src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs

+106-19
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,42 @@ Expression ParseIdentifier()
10451045
return expr;
10461046
}
10471047

1048+
//// This could be enum like "MyEnum.Value1"
1049+
//if (_textParser.CurrentToken.Id == TokenId.Identifier)
1050+
//{
1051+
// var parts = new List<string> { _textParser.CurrentToken.Text };
1052+
1053+
// _textParser.NextToken();
1054+
// _textParser.ValidateToken(TokenId.Dot, Res.DotExpected);
1055+
// while (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus)
1056+
// {
1057+
// parts.Add(_textParser.CurrentToken.Text);
1058+
1059+
// _textParser.NextToken();
1060+
// _textParser.ValidateToken(TokenId.Identifier, Res.IdentifierExpected);
1061+
1062+
// parts.Add(_textParser.CurrentToken.Text);
1063+
1064+
// _textParser.NextToken();
1065+
// }
1066+
1067+
// var enumTypeAsString = string.Join("", parts.Take(parts.Count - 2).ToArray());
1068+
// var enumType = _typeFinder.FindTypeByName(enumTypeAsString, null, true);
1069+
// if (enumType == null)
1070+
// {
1071+
// throw ParseError(_textParser.CurrentToken.Pos, Res.EnumTypeNotFound, enumTypeAsString);
1072+
// }
1073+
1074+
// string enumValue = parts.Last();
1075+
// var @enum = TypeHelper.ParseEnum(enumValue, enumType);
1076+
// if (@enum == null)
1077+
// {
1078+
// throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueNotDefined, enumValue, enumTypeAsString);
1079+
// }
1080+
1081+
// return Expression.Constant(@enum);
1082+
//}
1083+
10481084
if (_it != null)
10491085
{
10501086
return ParseMemberAccess(null, _it);
@@ -1682,10 +1718,9 @@ Expression ParseMemberAccess(Type type, Expression expression)
16821718
}
16831719
}
16841720

1685-
if (type.GetTypeInfo().IsEnum)
1721+
var @enum = TypeHelper.ParseEnum(id, type);
1722+
if (@enum != null)
16861723
{
1687-
var @enum = Enum.Parse(type, id, true);
1688-
16891724
return Expression.Constant(@enum);
16901725
}
16911726

@@ -1722,33 +1757,85 @@ Expression ParseMemberAccess(Type type, Expression expression)
17221757
return _expressionHelper.ConvertToExpandoObjectAndCreateDynamicExpression(expression, type, id);
17231758
}
17241759
#endif
1725-
1760+
// Parse as Lambda
17261761
if (_textParser.CurrentToken.Id == TokenId.Lambda && _it.Type == type)
17271762
{
1728-
// This might be an internal variable for use within a lambda expression, so store it as such
1729-
_internals.Add(id, _it);
1730-
string _previousItName = ItName;
1763+
return ParseAsLambda(id);
1764+
}
1765+
1766+
// This could be enum like "A.B.C.MyEnum.Value1" or "A.B.C+MyEnum.Value1"
1767+
if (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus)
1768+
{
1769+
return ParseAsEnum(id);
1770+
}
1771+
1772+
throw ParseError(errorPos, Res.UnknownPropertyOrField, id, TypeHelper.GetTypeName(type));
1773+
}
1774+
1775+
private Expression ParseAsLambda(string id)
1776+
{
1777+
// This might be an internal variable for use within a lambda expression, so store it as such
1778+
_internals.Add(id, _it);
1779+
string _previousItName = ItName;
1780+
1781+
// Also store ItName (only once)
1782+
if (string.Equals(ItName, KeywordsHelper.KEYWORD_IT))
1783+
{
1784+
ItName = id;
1785+
}
1786+
1787+
// next
1788+
_textParser.NextToken();
1789+
1790+
LastLambdaItName = ItName;
1791+
var exp = ParseConditionalOperator();
17311792

1732-
// Also store ItName (only once)
1733-
if (string.Equals(ItName, KeywordsHelper.KEYWORD_IT))
1793+
// Restore previous context and clear internals
1794+
_internals.Remove(id);
1795+
ItName = _previousItName;
1796+
1797+
return exp;
1798+
}
1799+
1800+
private Expression ParseAsEnum(string id)
1801+
{
1802+
var parts = new List<string> { id };
1803+
1804+
while (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus)
1805+
{
1806+
if (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus)
17341807
{
1735-
ItName = id;
1808+
parts.Add(_textParser.CurrentToken.Text);
1809+
_textParser.NextToken();
17361810
}
17371811

1738-
// next
1739-
_textParser.NextToken();
1812+
if (_textParser.CurrentToken.Id == TokenId.Identifier)
1813+
{
1814+
parts.Add(_textParser.CurrentToken.Text);
1815+
_textParser.NextToken();
1816+
}
1817+
}
17401818

1741-
LastLambdaItName = ItName;
1742-
var exp = ParseConditionalOperator();
1819+
var enumTypeAsString = string.Join("", parts.Take(parts.Count - 2).ToArray());
1820+
var enumType = _typeFinder.FindTypeByName(enumTypeAsString, null, true);
1821+
if (enumType == null)
1822+
{
1823+
throw ParseError(_textParser.CurrentToken.Pos, Res.EnumTypeNotFound, enumTypeAsString);
1824+
}
17431825

1744-
// Restore previous context and clear internals
1745-
_internals.Remove(id);
1746-
ItName = _previousItName;
1826+
string enumValueAsString = parts.LastOrDefault();
1827+
if (enumValueAsString == null)
1828+
{
1829+
throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueExpected);
1830+
}
17471831

1748-
return exp;
1832+
var enumValue = TypeHelper.ParseEnum(enumValueAsString, enumType);
1833+
if (enumValue == null)
1834+
{
1835+
throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueNotDefined, enumValueAsString, enumTypeAsString);
17491836
}
17501837

1751-
throw ParseError(errorPos, Res.UnknownPropertyOrField, id, TypeHelper.GetTypeName(type));
1838+
return Expression.Constant(enumValue);
17521839
}
17531840

17541841
Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type type)

src/System.Linq.Dynamic.Core/Res.cs

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ internal static class Res
2020
public const string DotOrOpenParenOrStringLiteralExpected = "'.' or '(' or string literal expected";
2121
public const string DynamicExpandoObjectIsNotSupported = "Dynamic / ExpandoObject is not supported in .NET 3.5, UAP and .NETStandard 1.3";
2222
public const string DuplicateIdentifier = "The identifier '{0}' was defined more than once";
23+
public const string EnumTypeNotFound = "Enum type '{0}' not found";
24+
public const string EnumValueExpected = "Enum value expected";
25+
public const string EnumValueNotDefined = "Enum value '{0}' is not defined in enum type '{1}'";
2326
public const string ExpressionExpected = "Expression expected";
2427
public const string ExpressionTypeMismatch = "Expression of type '{0}' expected";
2528
public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'";

0 commit comments

Comments
 (0)