Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using JetBrains.Annotations;
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
Expand All @@ -11,6 +10,7 @@
using System.Linq.Dynamic.Core.Validation;
using System.Linq.Expressions;
using System.Reflection;
using JetBrains.Annotations;

namespace System.Linq.Dynamic.Core.Parser
{
Expand Down Expand Up @@ -1861,7 +1861,28 @@ Expression ParseEnumerable(Expression instance, Type elementType, string methodN

private Type ResolveTypeFromArgumentExpression(string functionName, Expression argumentExpression)
{
string typeName = (argumentExpression as ConstantExpression)?.Value as string;
switch (argumentExpression)
{
case ConstantExpression constantExpression:
switch (constantExpression.Value)
{
case string typeName:
return ResolveTypeStringFromArgument(functionName, typeName);

case Type type:
return type;

default:
throw ParseError(_textParser.CurrentToken.Pos, Res.FunctionRequiresOneNotNullArgOfType, functionName, "string or System.Type");
}

default:
throw ParseError(_textParser.CurrentToken.Pos, Res.FunctionRequiresOneNotNullArgOfType, functionName, "ConstantExpression");
}
}

private Type ResolveTypeStringFromArgument(string functionName, string typeName)
{
if (string.IsNullOrEmpty(typeName))
{
throw ParseError(_textParser.CurrentToken.Pos, Res.FunctionRequiresOneNotNullArg, functionName, typeName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ internal interface IEnumerableSignatures
void Average(long? selector);
void Average(long selector);
void Cast(string type);
void Cast(Type type);
void Contains(object selector);
void Count();
void Count(bool predicate);
Expand All @@ -37,6 +38,7 @@ internal interface IEnumerableSignatures
void Max(object selector);
void Min(object selector);
void OfType(string type);
void OfType(Type type);
void OrderBy(object selector);
void OrderByDescending(object selector);
void Select(object selector);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ internal interface IQueryableSignatures
void Average(long? selector);
void Average(long selector);
void Cast(string type);
void Cast(Type type);
void Count();
void Count(bool predicate);
void DefaultIfEmpty();
Expand All @@ -36,6 +37,7 @@ internal interface IQueryableSignatures
void Max(object selector);
void Min(object selector);
void OfType(string type);
void OfType(Type type);
void OrderBy(object selector);
void OrderByDescending(object selector);
void Select(object selector);
Expand Down
1 change: 1 addition & 0 deletions src/System.Linq.Dynamic.Core/Res.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ internal static class Res
public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'";
public const string FunctionRequiresOneArg = "The '{0}' function requires one argument";
public const string FunctionRequiresOneNotNullArg = "The '{0}' function requires one argument which is not null.";
public const string FunctionRequiresOneNotNullArgOfType = "The '{0}' function requires one argument of type {1} which is not null.";
public const string HexCharExpected = "Hexadecimal character expected";
public const string IQueryableProviderNotAsync = "The provider for the source IQueryable doesn't implement IAsyncQueryProvider/IDbAsyncQueryProvider. Only providers that implement IAsyncQueryProvider/IDbAsyncQueryProvider can be used for Entity Framework asynchronous operations.";
public const string IdentifierExpected = "Identifier expected";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void OfType_WithString()
}

[Fact]
public void OfType_Dynamic()
public void OfType_Dynamic_WithFullName()
{
// Assign
var qry = new[]
Expand All @@ -64,6 +64,29 @@ public void OfType_Dynamic()
Check.That(oftypeDynamic.Length).Equals(oftype.Length);
}

[Fact]
public void OfType_Dynamic_WithType()
{
// Assign
var qry = new[]
{
new CompanyWithBaseEmployees
{
Employees = new BaseEmployee[]
{
new Worker { Name = "e" }, new Boss { Name = "e" }
}
}
}.AsQueryable();

// Act
var oftype = qry.Select(c => c.Employees.OfType<Worker>().Where(e => e.Name == "e")).ToArray();
var oftypeDynamic = qry.Select("Employees.OfType(@0).Where(Name == \"e\")", typeof(Worker)).ToDynamicArray();

// Assert
Check.That(oftypeDynamic.Length).Equals(oftype.Length);
}

[Fact]
public void Is_Dynamic_ActingOnIt()
{
Expand Down Expand Up @@ -103,6 +126,23 @@ public void Is_Dynamic_ActingOnIt_WithSimpleName()
Check.That(countOfTypeDynamic).Equals(countOfType);
}

[Fact]
public void Is_Dynamic_ActingOnIt_WithType()
{
// Assign
var qry = new BaseEmployee[]
{
new Worker { Name = "1" }, new Boss { Name = "b" }
}.AsQueryable();

// Act
int countOfType = qry.Count(c => c is Worker);
int countOfTypeDynamic = qry.Count("is(@0)", typeof(Worker));

// Assert
Check.That(countOfTypeDynamic).Equals(countOfType);
}

[Fact]
public void As_Dynamic_ActingOnIt()
{
Expand All @@ -119,6 +159,22 @@ public void As_Dynamic_ActingOnIt()
Check.That(countAsDynamic).Equals(1);
}

[Fact]
public void As_Dynamic_ActingOnIt_WithType()
{
// Assign
var qry = new BaseEmployee[]
{
new Worker { Name = "1" }, new Boss { Name = "b" }
}.AsQueryable();

// Act
int countAsDynamic = qry.Count("As(@0) != null", typeof(Worker));

// Assert
Check.That(countAsDynamic).Equals(1);
}

[Fact]
public void CastToType_WithType()
{
Expand Down Expand Up @@ -176,6 +232,29 @@ public void CastToType_Dynamic()
Check.That(cast.Length).Equals(castDynamic.Length);
}

[Fact]
public void CastToType_Dynamic_WithType()
{
// Assign
var qry = new[]
{
new CompanyWithBaseEmployees
{
Employees = new BaseEmployee[]
{
new Worker { Name = "e" }
}
}
}.AsQueryable();

// Act
var cast = qry.Select(c => c.Employees.Cast<Worker>().Where(e => e.Name == "e")).ToArray();
var castDynamic = qry.Select("Employees.Cast(@0).Where(Name == \"e\")", typeof(Worker)).ToDynamicArray();

// Assert
Check.That(cast.Length).Equals(castDynamic.Length);
}

[Fact]
public void CastToType_Dynamic_ActingOnIt()
{
Expand All @@ -193,6 +272,23 @@ public void CastToType_Dynamic_ActingOnIt()
Check.That(cast.Length).Equals(castDynamic.Length);
}

[Fact]
public void CastToType_Dynamic_ActingOnIt_WithType()
{
// Assign
var qry = new BaseEmployee[]
{
new Worker { Name = "1" }, new Worker { Name = "2" }
}.AsQueryable();

// Act
var cast = qry.Select(c => (Worker)c).ToArray();
var castDynamic = qry.Select("Cast(@0)", typeof(Worker)).ToDynamicArray();

// Assert
Check.That(cast.Length).Equals(castDynamic.Length);
}

[Fact]
public void CastToType_Dynamic_ActingOnIt_Throws()
{
Expand Down