【发布时间】:2017-09-30 03:36:04
【问题描述】:
这是我无法理解的事情。我在 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 开始才支持将 ref 返回到引用类型。
那么这是怎么发生的呢?我错过了什么吗?编译器是否在做一些诡计来实现这一点?因为,我不是在抱怨这种行为。在这种情况下,这似乎是您想要发生的事情。但我只是对不一致的行为感到惊讶。
谢谢。我希望这不是我错过的真正微不足道的东西。
【问题讨论】:
-
在你的脑海中,尝试将
persons[0]替换为persons.Index0,看看你是否能看出persons.Index0 = new Person("Modified");和pppp = new Person("Modified");之间的区别,我想它会变得清晰。 -
是的,你用指向新对象的指针覆盖了指针,而不是对象本身
-
我想它现在已经清理干净了。我不知道为什么我的印象是 people[0] 将返回(调用索引器的 get)以返回我期望覆盖的副本。但实际上它正在调用索引器的设置器。并传入对新对象的引用。多谢你们!我想我希望它能够像在 C++ 中一样工作(如果我没记错的话,它就是这样工作的,对吧?)
-
C++ 的工作原理完全相同(如果您始终将 C#
Person映射到 C++ 的Person*) -
@AlexeiLevenkov:我在 C++ 方面不是很有经验,所以也许我遗漏了一些东西,但是下面的代码对我来说表现不同。下标运算符返回对内部对象的引用,而在 C# 中,没有任何内容返回给调用者,而是作为参数接收。现在我看到它,我对其他事情感到困惑。我的印象是 C++ 引用不能指向其他对象,这与指针不同。那么为什么我可以将返回的引用指向下面的 C++ 示例中的新对象:
标签: c# indexing reference return