diff --git a/src/System.Linq.Dynamic.Core/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/ExpressionParser.cs index 2c5dca1c..74dd6517 100644 --- a/src/System.Linq.Dynamic.Core/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/ExpressionParser.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel; using System.Linq.Expressions; using System.Reflection; using System.Collections; @@ -633,6 +634,10 @@ Expression ParseComparison() _token.id == TokenId.GreaterThan || _token.id == TokenId.GreaterThanEqual || _token.id == TokenId.LessThan || _token.id == TokenId.LessThanEqual) { + ConstantExpression constantExpr; +#if !SILVERLIGHT + TypeConverter typeConverter; +#endif Token op = _token; NextToken(); Expression right = ParseShift(); @@ -659,8 +664,6 @@ Expression ParseComparison() { if (left.Type != right.Type) { - ConstantExpression constantExpr; - Expression e; if ((e = PromoteExpression(right, left.Type, true)) != null) { @@ -702,6 +705,16 @@ Expression ParseComparison() } } } +#if !SILVERLIGHT + else if ((constantExpr = right as ConstantExpression) != null && constantExpr.Value is string && (typeConverter = TypeDescriptor.GetConverter(left.Type)) != null) + { + right = Expression.Constant(typeConverter.ConvertFromInvariantString((string)constantExpr.Value), left.Type); + } + else if ((constantExpr = left as ConstantExpression) != null && constantExpr.Value is string && (typeConverter = TypeDescriptor.GetConverter(right.Type)) != null) + { + left = Expression.Constant(typeConverter.ConvertFromInvariantString((string)constantExpr.Value), right.Type); + } +#endif else { CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), @@ -1288,7 +1301,7 @@ static Expression GenerateConversion(Expression expr, Type type, int errorPos) return Expression.Constant(dateTime, type); object[] arguments = { text, null }; -#if NETFX_CORE ||WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD +#if NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD MethodInfo method = type.GetMethod("TryParse", new[] { typeof(string), type.MakeByRefType() }); #else MethodInfo method = type.GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(string), type.MakeByRefType() }, null); @@ -1582,7 +1595,7 @@ static bool IsUnsignedIntegralType(Type type) static int GetNumericTypeKind(Type type) { type = GetNonNullableType(type); -#if !(NETFX_CORE ||WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) +#if !(NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) if (type.GetTypeInfo().IsEnum) return 0; switch (Type.GetTypeCode(type)) @@ -1650,7 +1663,7 @@ static Exception IncompatibleOperandsError(string opName, Expression left, Expre static MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess) { -#if !(NETFX_CORE ||WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) +#if !(NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); foreach (Type t in SelfAndBaseTypes(type)) { @@ -1680,7 +1693,7 @@ static MemberInfo FindPropertyOrField(Type type, string memberName, bool staticA int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method) { -#if !(NETFX_CORE ||WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) +#if !(NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); foreach (Type t in SelfAndBaseTypes(type)) @@ -1709,7 +1722,7 @@ int FindIndexer(Type type, Expression[] args, out MethodBase method) { foreach (Type t in SelfAndBaseTypes(type)) { -#if !(NETFX_CORE ||WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) +#if !(NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) MemberInfo[] members = t.GetDefaultMembers(); #else MemberInfo[] members = new MemberInfo[0]; @@ -1718,7 +1731,7 @@ int FindIndexer(Type type, Expression[] args, out MethodBase method) { IEnumerable methods = members .OfType(). -#if !(NETFX_CORE ||WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) +#if !(NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) Select(p => (MethodBase)p.GetGetMethod()). Where(m => m != null); #else @@ -1831,7 +1844,7 @@ Expression PromoteExpression(Expression expr, Type type, bool exact) { Type target = GetNonNullableType(type); object value = null; -#if !(NETFX_CORE ||WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) +#if !(NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) switch (Type.GetTypeCode(ce.Type)) { case TypeCode.Int32: @@ -1880,7 +1893,7 @@ Expression PromoteExpression(Expression expr, Type type, bool exact) static object ParseNumber(string text, Type type) { -#if !(NETFX_CORE ||WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) +#if !(NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) switch (Type.GetTypeCode(GetNonNullableType(type))) { case TypeCode.SByte: @@ -1991,7 +2004,7 @@ static object ParseNumber(string text, Type type) static object ParseEnum(string name, Type type) { -#if !(NETFX_CORE ||WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) +#if !(NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) if (type.IsEnum) { MemberInfo[] memberInfos = type.FindMembers(MemberTypes.Field, @@ -2010,7 +2023,7 @@ static object ParseEnum(string name, Type type) static bool IsCompatibleWith(Type source, Type target) { -#if !(NETFX_CORE ||WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) +#if !(NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD) if (source == target) return true; if (!target.IsValueType) return target.IsAssignableFrom(source); Type st = GetNonNullableType(source); diff --git a/src/System.Linq.Dynamic.Core/project.json b/src/System.Linq.Dynamic.Core/project.json index 04ffa078..4aee9b1f 100644 --- a/src/System.Linq.Dynamic.Core/project.json +++ b/src/System.Linq.Dynamic.Core/project.json @@ -42,32 +42,51 @@ }, "net45": { "frameworkAssemblies": { + }, + "dependencies": { + "System.ComponentModel.TypeConverter": "4.1.0" } }, "net451": { "frameworkAssemblies": { + }, + "dependencies": { + "System.ComponentModel.TypeConverter": "4.1.0" } }, "net452": { "frameworkAssemblies": { + }, + "dependencies": { + "System.ComponentModel.TypeConverter": "4.1.0" } }, "net46": { "frameworkAssemblies": { + }, + "dependencies": { + "System.ComponentModel.TypeConverter": "4.1.0" } }, "net461": { "frameworkAssemblies": { + }, + "dependencies": { + "System.ComponentModel.TypeConverter": "4.1.0" } }, "dnx451": { "frameworkAssemblies": { + }, + "dependencies": { + "System.ComponentModel.TypeConverter": "4.1.0" } }, "netcore45": { "buildOptions": { "define": [ "WINDOWS_APP" ] }, "dependencies": { "System.Collections.Concurrent": "4.0.10", + "System.ComponentModel.TypeConverter": "4.1.0", "System.Dynamic.Runtime": "4.0.0", "System.Linq": "4.0.0", "System.Linq.Expressions": "4.0.0", @@ -82,6 +101,7 @@ "buildOptions": { "define": [ "WINDOWS_APP" ] }, "dependencies": { "System.Collections.Concurrent": "4.0.10", + "System.ComponentModel.TypeConverter": "4.1.0", "System.Dynamic.Runtime": "4.0.0", "System.Linq": "4.0.0", "System.Linq.Expressions": "4.0.0", @@ -96,6 +116,7 @@ "buildOptions": { "define": [ "WINDOWS_APP" ] }, "dependencies": { "System.Collections.Concurrent": "4.0.12", + "System.ComponentModel.TypeConverter": "4.1.0", "System.Diagnostics.Debug": "4.0.11", "System.Dynamic.Runtime": "4.0.11", "System.Globalization": "4.0.11", @@ -114,6 +135,7 @@ ], "dependencies": { "System.Collections.Concurrent": "4.0.12", + "System.ComponentModel.TypeConverter": "4.1.0", "System.Diagnostics.Debug": "4.0.11", "System.Dynamic.Runtime": "4.0.11", "System.Globalization": "4.0.11", @@ -142,6 +164,7 @@ "dependencies": { "System.Collections": "4.0.11", "System.Collections.Concurrent": "4.0.12", + "System.ComponentModel.TypeConverter": "4.1.0", "System.Diagnostics.Debug": "4.0.11", "System.Dynamic.Runtime": "4.0.11", "System.Linq.Expressions": "4.1.0", diff --git a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs index 7cdbc74b..567bde66 100644 --- a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs @@ -469,6 +469,39 @@ public void ExpressionTests_Enum() Assert.Equal(TestEnum.Var5, result6.Single()); } + [Fact] + public void ExpressionTests_DateTimeString() + { + GlobalConfig.CustomTypeProvider = new NetStandardCustomTypeProvider(); + + //Arrange + var lst = new List { DateTime.Today, DateTime.Today.AddDays(1), DateTime.Today.AddDays(2) }; + var qry = lst.AsQueryable(); + + //Act + var result1 = qry.Where("it = @0", lst[0].ToString()); + + //Assert + Assert.Equal(lst[0], result1.Single()); + } + + [Fact] + public void ExpressionTests_GuidString() + { + GlobalConfig.CustomTypeProvider = new NetStandardCustomTypeProvider(); + + //Arrange + var lst = new List { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; + var qry = lst.AsQueryable(); + + //Act + var result1 = qry.Where("it = @0", lst[0].ToString()); + + //Assert + Assert.Equal(lst[0], result1.Single()); + } + + [Fact] public void ExpressionTests_CompareWithGuid() {