Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify and minimize expression containers. #448

Merged
merged 1 commit into from
Mar 9, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public static IQueryable<T> Include<T>(this IQueryable<T> source, IncludeExpress
public static IQueryable<T> ThenInclude<T>(this IQueryable<T> source, IncludeExpressionInfo info)
{
_ = info ?? throw new ArgumentNullException(nameof(info));
_ = info.PreviousPropertyType ?? throw new ArgumentNullException(nameof(info.PreviousPropertyType));

var exp = source.Expression as MethodCallExpression;
var arg = exp.Arguments[0] as ConstantExpression;
Expand Down Expand Up @@ -47,7 +46,7 @@ public static IQueryable<T> ThenInclude<T>(this IQueryable<T> source, IncludeExp
return QueryableExtensions.Include(source, $"{previousPropertyName}.{propertyName}");
}

private static string GetPropertyName(this Expression propertySelector, char delimiter = '.', char endTrim = ')')
private static string GetPropertyName(this LambdaExpression propertySelector, char delimiter = '.', char endTrim = ')')
{

var asString = propertySelector.ToString();
Expand Down
12 changes: 6 additions & 6 deletions src/Ardalis.Specification/Builders/Builder_Include.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public static IIncludableSpecificationBuilder<T, TResult, TProperty> Include<T,
{
if (condition)
{
var expr = new IncludeExpressionInfo(navigationSelector, typeof(T), typeof(TProperty));
var expr = new IncludeExpressionInfo(navigationSelector, IncludeTypeEnum.Include);
builder.Specification.Add(expr);
}

Expand Down Expand Up @@ -139,7 +139,7 @@ public static IIncludableSpecificationBuilder<T, TProperty> Include<T, TProperty
{
if (condition)
{
var expr = new IncludeExpressionInfo(navigationSelector, typeof(T), typeof(TProperty));
var expr = new IncludeExpressionInfo(navigationSelector, IncludeTypeEnum.Include);
builder.Specification.Add(expr);
}

Expand Down Expand Up @@ -183,7 +183,7 @@ public static IIncludableSpecificationBuilder<TEntity, TResult, TProperty> ThenI
{
if (condition && !Specification<TEntity, TResult>.IsChainDiscarded)
{
var expr = new IncludeExpressionInfo(navigationSelector, typeof(TEntity), typeof(TProperty), typeof(TPreviousProperty));
var expr = new IncludeExpressionInfo(navigationSelector, IncludeTypeEnum.ThenInclude);
builder.Specification.Add(expr);
}
else
Expand Down Expand Up @@ -228,7 +228,7 @@ public static IIncludableSpecificationBuilder<TEntity, TProperty> ThenInclude<TE
{
if (condition && !Specification<TEntity>.IsChainDiscarded)
{
var expr = new IncludeExpressionInfo(navigationSelector, typeof(TEntity), typeof(TProperty), typeof(TPreviousProperty));
var expr = new IncludeExpressionInfo(navigationSelector, IncludeTypeEnum.ThenInclude);
builder.Specification.Add(expr);
}
else
Expand Down Expand Up @@ -275,7 +275,7 @@ public static IIncludableSpecificationBuilder<TEntity, TResult, TProperty> ThenI
{
if (condition && !Specification<TEntity, TResult>.IsChainDiscarded)
{
var expr = new IncludeExpressionInfo(navigationSelector, typeof(TEntity), typeof(TProperty), typeof(IEnumerable<TPreviousProperty>));
var expr = new IncludeExpressionInfo(navigationSelector, IncludeTypeEnum.ThenInclude);
builder.Specification.Add(expr);
}
else
Expand Down Expand Up @@ -320,7 +320,7 @@ public static IIncludableSpecificationBuilder<TEntity, TProperty> ThenInclude<TE
{
if (condition && !Specification<TEntity>.IsChainDiscarded)
{
var expr = new IncludeExpressionInfo(navigationSelector, typeof(TEntity), typeof(TProperty), typeof(IEnumerable<TPreviousProperty>));
var expr = new IncludeExpressionInfo(navigationSelector, IncludeTypeEnum.ThenInclude);
builder.Specification.Add(expr);
}
else
Expand Down
62 changes: 1 addition & 61 deletions src/Ardalis.Specification/Expressions/IncludeExpressionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,76 +11,16 @@ public class IncludeExpressionInfo
/// </summary>
public LambdaExpression LambdaExpression { get; }

/// <summary>
/// The type of the source entity.
/// </summary>
public Type EntityType { get; }

/// <summary>
/// The type of the included entity.
/// </summary>
public Type PropertyType { get; }

/// <summary>
/// The type of the previously included entity.
/// </summary>
public Type? PreviousPropertyType { get; }

/// <summary>
/// The include type.
/// </summary>
public IncludeTypeEnum Type { get; }

private IncludeExpressionInfo(LambdaExpression expression,
Type entityType,
Type propertyType,
Type? previousPropertyType,
IncludeTypeEnum includeType)

public IncludeExpressionInfo(LambdaExpression expression, IncludeTypeEnum includeType)
{
_ = expression ?? throw new ArgumentNullException(nameof(expression));
_ = entityType ?? throw new ArgumentNullException(nameof(entityType));
_ = propertyType ?? throw new ArgumentNullException(nameof(propertyType));

if (includeType == IncludeTypeEnum.ThenInclude)
{
_ = previousPropertyType ?? throw new ArgumentNullException(nameof(previousPropertyType));
}

LambdaExpression = expression;
EntityType = entityType;
PropertyType = propertyType;
PreviousPropertyType = previousPropertyType;
Type = includeType;
}

/// <summary>
/// Creates instance of <see cref="IncludeExpressionInfo" /> which describes 'Include' query part.<para />
/// Source (entityType) -> Include (propertyType).
/// </summary>
/// <param name="expression">The expression represents a related entity that should be included.</param>
/// <param name="entityType">The type of the source entity.</param>
/// <param name="propertyType">The type of the included entity.</param>
public IncludeExpressionInfo(LambdaExpression expression,
Type entityType,
Type propertyType)
: this(expression, entityType, propertyType, null, IncludeTypeEnum.Include)
{
}

/// <summary>
/// Creates instance of <see cref="IncludeExpressionInfo" /> which describes 'ThenInclude' query part.<para />
/// Source (entityType) -> Include (previousPropertyType) -> ThenInclude (propertyType).
/// </summary>
/// <param name="expression">The expression represents a related entity that should be included as part of the previously included entity.</param>
/// <param name="entityType">The type of the source entity.</param>
/// <param name="propertyType">The type of the included entity.</param>
/// <param name="previousPropertyType">The type of the previously included entity.</param>
public IncludeExpressionInfo(LambdaExpression expression,
Type entityType,
Type propertyType,
Type previousPropertyType)
: this(expression, entityType, propertyType, previousPropertyType, IncludeTypeEnum.ThenInclude)
{
}
}
6 changes: 2 additions & 4 deletions src/Ardalis.Specification/Expressions/OrderExpressionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/// <typeparam name="T">Type of the entity to apply sort on.</typeparam>
public class OrderExpressionInfo<T>
{
private readonly Lazy<Func<T, object?>> _keySelectorFunc;
private Func<T, object?>? _keySelectorFunc;

/// <summary>
/// Creates instance of <see cref="OrderExpressionInfo{T}" />.
Expand All @@ -20,8 +20,6 @@ public OrderExpressionInfo(Expression<Func<T, object?>> keySelector, OrderTypeEn

KeySelector = keySelector;
OrderType = orderType;

_keySelectorFunc = new Lazy<Func<T, object?>>(KeySelector.Compile);
}

/// <summary>
Expand All @@ -37,5 +35,5 @@ public OrderExpressionInfo(Expression<Func<T, object?>> keySelector, OrderTypeEn
/// <summary>
/// Compiled <see cref="KeySelector" />.
/// </summary>
public Func<T, object?> KeySelectorFunc => _keySelectorFunc.Value;
public Func<T, object?> KeySelectorFunc => _keySelectorFunc ??= KeySelector.Compile();
}
6 changes: 2 additions & 4 deletions src/Ardalis.Specification/Expressions/SearchExpressionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/// <typeparam name="T">Type of the source from which search target should be selected.</typeparam>
public class SearchExpressionInfo<T>
{
private readonly Lazy<Func<T, string?>> _selectorFunc;
private Func<T, string?>? _selectorFunc;

/// <summary>
/// Creates instance of <see cref="SearchExpressionInfo{T}" />.
Expand All @@ -24,8 +24,6 @@ public SearchExpressionInfo(Expression<Func<T, string?>> selector, string search
Selector = selector;
SearchTerm = searchTerm;
SearchGroup = searchGroup;

_selectorFunc = new Lazy<Func<T, string?>>(Selector.Compile);
}

/// <summary>
Expand All @@ -46,5 +44,5 @@ public SearchExpressionInfo(Expression<Func<T, string?>> selector, string search
/// <summary>
/// Compiled <see cref="Selector" />.
/// </summary>
public Func<T, string?> SelectorFunc => _selectorFunc.Value;
public Func<T, string?> SelectorFunc => _selectorFunc ??= Selector.Compile();
}
7 changes: 2 additions & 5 deletions src/Ardalis.Specification/Expressions/WhereExpressionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/// <typeparam name="T">Type of the entity to apply filter on.</typeparam>
public class WhereExpressionInfo<T>
{
private readonly Lazy<Func<T, bool>> _filterFunc;
private Func<T, bool>? _filterFunc;

/// <summary>
/// Creates instance of <see cref="WhereExpressionInfo{T}" />.
Expand All @@ -16,10 +16,7 @@ public class WhereExpressionInfo<T>
public WhereExpressionInfo(Expression<Func<T, bool>> filter)
{
_ = filter ?? throw new ArgumentNullException(nameof(filter));

Filter = filter;

_filterFunc = new Lazy<Func<T, bool>>(Filter.Compile);
}

/// <summary>
Expand All @@ -30,5 +27,5 @@ public WhereExpressionInfo(Expression<Func<T, bool>> filter)
/// <summary>
/// Compiled <see cref="Filter" />.
/// </summary>
public Func<T, bool> FilterFunc => _filterFunc.Value;
public Func<T, bool> FilterFunc => _filterFunc ??= Filter.Compile();
}