Skip to content

Conversation

@victorr99
Copy link

The ExpressionParser was updated with a new method allowing case insensitive compares whenever this was configured in the ParserConfig.

The method CanonicalContains performs a case insensitive check whenever IsCaseSensitive was set to false. It also updates the provided needle parameter to the actual found value. Thus a match on max will be translated to Max.

This fixes issue #967

Copy link
Collaborator

@StefH StefH left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And will this not break any code where a Class has a property max?

Like

public class X
{
  public string max { get ; set; }

   public string MAX { get ; set; }
}

Maybe add a unit test for this.

return true;
}

private bool CanonicalContains(string[] haystack, ref string needle)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to use ref

just do:

if (_parsingConfig.IsCaseSensitive)
{
    return haystack.Contains(needle);
}

return haystack.Any(s => string.Equals(s, value, StringComparison.OrdinalIgnoreCase));

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed the method to just Contains. It indeed works without using ref, so I've removed that.
I've tried to add some unit tests with a max property. Is this what you had in mind?

- Tests added for a model with a max property
- CanonicalContains is now just Contains without ref string needle
@victorr99 victorr99 requested a review from StefH December 6, 2025 13:04
@victorr99
Copy link
Author

@StefH can you have a look again at the PR?

@victorr99
Copy link
Author

@StefH any updates?

@StefH
Copy link
Collaborator

StefH commented Jan 14, 2026

I'm still thinking about backward compatibility...

@victorr99
Copy link
Author

The only compatability issue I can think of is that a custom enumerable object is being used which specifies Min and Max methods on its own. Think of the following class:

public class CustomEnumerable<T> : IEnumerable<T>
{
    public int Max { get; set; }

    public int Min()
    {
    }
}

The Max property can easily be distinguished from the method because the parantheses makes it a method, unless it's a delegate like Func<int>. For the Min method and (the Func<int> Max property), the implementation of the CustomEnumerable should be choosen.
I have never needed to use a custom enumerable class, but I can imagine that there are use cases for that. I can add extra tests which checks that the methods of the custom enumerable are choosen over the extension methods, however I don't think proper support for custom enumerables has ever existed. The following code returns 15, but it should return 0:

public class CustomEnumerable<T>(IEnumerable<T> inner) : IEnumerable<T>
{
    public T Max { get; set; }

    public DateTime Min()
    {
        return default;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return inner.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

var parameter = Expression.Parameter(typeof(CustomEnumerable<int>), "list");

var parser = new ExpressionParser(
    [parameter],
    "list.Min()",
    [],
    new ParsingConfig { IsCaseSensitive = false });

var expression = parser.Parse(typeof(int));
var lambda = Expression.Lambda<Func<CustomEnumerable<int>, int>>(expression, parameter);
var method = lambda.CompileFast();

Console.WriteLine(method(new CustomEnumerable<int>([15])));

So, I assume fixing it the right way introduces another backward compatability issue, or the CustomEnumerable example is a new bug.

By the way, you asked for extra tests which covers the Min and Max properties on a class. I don't think it adds extra value to the other test cases since LING is being applied to an enumerable of objects. It is not an extension for that object/class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants