在 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;
}
这是为什么?
这是因为当您编写
person.Firstname = ...
时,您正在调用 FirstName
的属性设置器,它会更改实例的数据。
相反,Where
不会改变它所调用的IEnumerable
,而是会产生一个新的IEnumerable
。
这些问题针对的是语言的基础知识。因此值得更准确的解释。
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
是一个引用类型变量,这意味着它不是持有对象本身,而是持有对象实际存储位置的引用。与引用类型一样,在赋值时,对象的引用(对象的地址)将被复制到赋值左侧的新变量。在对
people
变量进行赋值之前(如 people = people.Where( ...)
中,被调用方法中的引用类型变量和调用者中的变量,两者都引用同一个对象。
无论我使用什么变量来改变对象的状态,重要的是对象的状态已经改变,并且任何引用该对象的人都可以看到它已经改变!
innerPeople = innerPeople.Where ...
时会发生什么:innerPeople = innerPeople.Where ...
的右侧正在创建一个新对象。完成此分配后,innerPeople
指向的对象不是 outerPeople
所指向的对象!从这一点开始,被调用方法内的innerPeople
与外部作用域中的变量无关!