Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying IQueryable like a Reference Type doesn't work?

It's common in C# to modify objects in private methods as they are commonly reference-types instead of value types, for example:

public void Main()
{
    var person = new Person();

    SetPersonsName(person);

    System.Writeln(person.Firstname + " " + person.Lastname);
}

private void SetPersonsName(Person person)
{
    person.Firstname = "Jimi";
    person.Lastname = "Hendrix";
}

Firstname and Lastname are applied to the object and will be correctly printed as we pass in the object by reference (pointer to it's location in memory) rather than creating a copy of the object like we'd do for value-types.

So what if we have an IQueryable and which to use the same approach to add Where clauses to the object collection, like below?

public void Main()
{
    // Returns Jimi Hendrix and Justin Bieber
    var people = _workspace.GetDataSource<Person>();

    FilterByRockGods(people);

    foreach(var person in people)
    {
        // Will still print "Jimi Hendrix" and "Justin Bieber"
        // Should only print "Jimi Hendrix" (obviously)
        System.Writeln(person.Firstname + " " + person.Lastname);
    }
}

private void FilterByRockGods(IQueryable<Person> people)
{
    people = people.Where(x => x.IsRockGod);
}

This won't work, the Where clause applied in the private method is not applied to the collection

You have to do the following instead:

public void Main()
{
    // Returns Jimi Hendrix and Justin Bieber
    var people = _workspace.GetDataSource<Person>();

    people = FilterByRockGods(people);

    foreach(var person in people)
    {
        // Prints "Jimi Hendrix"
        System.Writeln(person.Firstname + " " + person.Lastname);
    }
}

private IQueryable<Person> FilterByRockGods(IQueryable<Person> people)
{
    people = people.Where(x => x.IsRockGod);

    return people;
}

Why is this?

like image 259
Luke Merrett Avatar asked Oct 20 '14 10:10

Luke Merrett


1 Answers

This is because when you write person.Firstname = ... you are invoking the FirstName's property setter which alters the instance's data.

Where, in contrast does not alter the IEnumerable it's called on but produces a new IEnumerable.

like image 191
vc 74 Avatar answered Oct 26 '22 23:10

vc 74