这是我无法理解的事情。我在C#中有以下示例代码:
class TestProgram
{
static void Main()
{
var scenario = new Scenario(10);
var persons = scenario.GetPersons(); //returns copy of reference pointing to internal List
persons[0] = new Person("Modified"); //why does index operator return actual object, and not a copy of the reference to the object, as below?
Console.WriteLine(scenario.Persons[0].Name); //internal List was modified
Console.WriteLine("Point to same object: " + (persons[0] == scenario.Persons[0])); //both refs point to the same object
var pppp = scenario.GetP(); //returns copy of the reference pointing to internal object
pppp = new Person("Modified"); //overwriting copy of reference has no impact on original object, as expected
Console.WriteLine(scenario.p.Name);
Console.WriteLine("Point to same object: " + (pppp == scenario.p));
var pppp2 = scenario[0]; //returns copy of the reference pointing to internal object
pppp2 = new Person("Modified"); //overwriting copy of reference has no impact on original object, as expected
Console.WriteLine(scenario.p.Name);
Console.WriteLine("Point to same object: " + (pppp2 == scenario.p));
Console.ReadKey();
}
}
public class Person
{
public string Name { get; set; }
public Person(string name)
{
Name = name;
}
}
public class Scenario
{
public Person p = new Person("DDD");
public Person GetP()
{
return p;
}
public Person this[int index]
{
get { return p; }
}
public IList<Person> Persons;
public Scenario(int nrPersons)
{
Persons = new List<Person>(nrPersons);
for(int i = 0; i < nrPersons; i++)
Persons.Add(new Person("DDD"));
}
public IList<Person> GetPersons()
{
return Persons;
}
}
所以,我的问题是为什么List的索引运算符似乎返回内部对象?我的印象是,在传递/返回引用类型时,方法/重载操作符将默认复制并按值返回。意味着应返回指向同一对象的新引用。与后续的pppp和pppp2引用一样,它的行为与预期的一样。
我看过dotpeek的List实现,并没有看到任何透露。从我所知的能够返回引用类型的引用只能从C#7.0开始支持。
那么这是怎么发生的?我错过了什么吗?编译器是否正在做一些技巧来实现这一目标?因为,我不是在抱怨这种行为。看起来这就是你想要在这种情况下发生的事情。但我对这种不一致的行为感到惊讶。
感谢。我希望我失踪并不是真正微不足道的事情。
答案 0 :(得分:0)
您在描述的行为 - 传递引用与引用的副本 - 在方法之间传递参数时适用。如果您包含ref
关键字,则会传递参考。否则,默认情况下它是参考文献的副本。
List
的目的是包含一组对象的引用,并能够维护该集合。因此,如果你这样做,可以预料到:
persons[0] = new Person("Modified");
您正在使用新引用替换之前在该列表中第一个位置保留的任何引用。
执行此操作时:
var pppp2 = scenario[0];
您正在创建一个变量,该变量包含对Scenario
实例的引用。然后,您可以使用不同的引用(或null
。)
在这两种情况下,你真的都在做同样的事情。将persons
视为引用的集合,persons[0]
是该集合中的单个引用。无论您是更新变量(pppp2
)还是列表元素(persons[0]
),都要更新它包含的参考。