'C# - Adding condition to func results in stack overflow exception

I have a func as part of specification class which sorts the given iqueryable

Func<IQueryable<T>, IOrderedQueryable<T>>? Sort { get; set; }

When i add more than one condition to the func like below , it results in stack overflow exception.

spec.OrderBy(sc => sc.Case.EndTime).OrderBy(sc => sc.Case.StartTime);

The OrderBy method is implemented like this

public ISpecification<T> OrderBy<TProperty>(Expression<Func<T, TProperty>> property)
    {
        _ = Sort == null ? Sort = items => items.OrderBy(property) : Sort = items => Sort(items).ThenBy(property);
        return this;
    }

Chaining or using separate lines doesn't make a difference.

This problem gets resolved if I assign a new instance of the specification and set it's func, but i don't want to be assigning to a new instance everytime. Please suggest what am i missing here and how to reuse the same instance (if possible).



Solution 1:[1]

This is the problematic part:

Sort = items => Sort(items)

That's like writing a method that calls itself.

What you want is to evaluate the existing Sort function, not "the result of the Sort property at the time of evaluation".

I would rewrite the method like this:

public ISpecification<T> OrderBy<TProperty>(Expression<Func<T, TProperty>> property)
{
    var existingSort = Sort;
    Sort = existingSort is null
        ? items => items.OrderBy(property)
        : items => existingSort(items).ThenBy(property);
    return this;
}

(I would also echo D-Shih's comment - this is a somewhat counter-intuitive approach, and counter to normal LINQ. Maybe you have some particular reason to go against LINQ's expectations of immutability and chaining, but it's definitely unusual.)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jon Skeet