Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would you refactor this LINQ code?

I've got a lot of ugly code that looks like this:

if (!string.IsNullOrEmpty(ddlFileName.SelectedItem.Text))
    results = results.Where(x => x.FileName.Contains(ddlFileName.SelectedValue));
if (chkFileName.Checked)
    results = results.Where(x => x.FileName == null);

if (!string.IsNullOrEmpty(ddlIPAddress.SelectedItem.Text))
    results = results.Where(x => x.IpAddress.Contains(ddlIPAddress.SelectedValue));
if (chkIPAddress.Checked)
    results = results.Where(x => x.IpAddress == null);

...etc.

results is an IQueryable<MyObject>.
The idea is that for each of these innumerable dropdowns and checkboxes, if the dropdown has something selected, the user wants to match that item. If the checkbox is checked, the user wants specifically those records where that field is null or an empty string. (The UI doesn't let both be selected at the same time.) This all adds to the LINQ Expression which gets executed at the end, after we've added all the conditions.

It seems like there ought to be some way to pull out an Expression<Func<MyObject, bool>> or two so that I can put the repeated parts in a method and just pass in what changes. I've done this in other places, but this set of code has me stymied. (Also, I'd like to avoid "Dynamic LINQ", because I want to keep things type-safe if possible.) Any ideas?

like image 312
Ryan Lundy Avatar asked Jun 10 '26 12:06

Ryan Lundy


1 Answers

In that case:

//list of predicate functions to check
var conditions = new List<Predicate<MyClass>> 
{
    x => string.IsNullOrEmpty(ddlFileName.SelectedItem.Text) ||
         x.FileName.Contains(ddlFileName.SelectedValue),
    x => !chkFileName.Checked ||
         string.IsNullOrEmpty(x.FileName),
    x => string.IsNullOrEmpty(ddlIPAddress.SelectedItem.Text) ||
         x.IpAddress.Contains(ddlIPAddress.SelectedValue),
    x => !chkIPAddress.Checked ||
         string.IsNullOrEmpty(x.IpAddress)
}

//now get results
var results =
    from x in GetInitialResults()
    //all the condition functions need checking against x
    where conditions.All( cond => cond(x) )
    select x;

I've just explicitly declared the predicate list, but these could be generated, something like:

ListBoxControl lbc;
CheckBoxControl cbc;
foreach( Control c in this.Controls)
    if( (lbc = c as ListBoxControl ) != null )
         conditions.Add( ... );
    else if ( (cbc = c as CheckBoxControl ) != null )
         conditions.Add( ... );

You would need some way to check the property of MyClass that you needed to check, and for that you'd have to use reflection.

like image 70
Keith Avatar answered Jun 13 '26 02:06

Keith



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!