像引用类型一样修改 IQueryable 不起作用?

问题描述 投票:0回答:2

在 C# 中修改私有方法中的对象很常见,因为它们通常是引用类型而不是值类型,例如:

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 和 Lastname 应用于对象,并且当我们通过引用(指向其在内存中的位置的指针)传入对象时,它们将被正确打印,而不是像我们为值类型所做的那样创建对象的副本。

那么如果我们有一个 IQueryable 并使用相同的方法将Where子句添加到对象集合中会怎样,如下所示?

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);
}

这是行不通的,私有方法中应用的Where子句不会应用于集合

您必须执行以下操作:

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;
}

这是为什么?

c# linq iqueryable
2个回答
8
投票

这是因为当您编写

person.Firstname = ...
时,您正在调用
FirstName
的属性设置器,它会更改实例的数据。

相反,

Where
不会改变它所调用的
IEnumerable
,而是会产生一个新的
IEnumerable


0
投票

这些问题针对的是语言的基础知识。因此值得更准确的解释。

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

    outerPeople = FilterByRockGods(people);

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

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

    return innerPeople;
}

执行
outerPeople = FilterByRockGods(people);
时会发生什么

people
是一个引用类型变量,这意味着它不是持有对象本身,而是持有对象实际存储位置的引用。与引用类型一样,在赋值时,对象的引用(对象的地址)将被复制到赋值左侧的新变量。
将参数传递给方法本身包括赋值语句。分配完成后我们可以这样说明:
enter image description here

在对

people
变量进行赋值之前(如
people = people.Where( ...)
中,被调用方法中的引用类型变量和调用者中的变量,两者都引用同一个对象

无论我使用什么变量来改变对象的状态,重要的是对象的状态已经改变,并且任何引用该对象的人都可以看到它已经改变!

执行
innerPeople = innerPeople.Where ...
时会发生什么:

innerPeople = innerPeople.Where ...
的右侧正在创建一个新对象。完成此分配后,
innerPeople
指向的对象不是
outerPeople
所指向的对象!从这一点开始,被调用方法内的
innerPeople
与外部作用域中的变量无关!
enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.