Присвоение переменной типа «Assembly» создаёт копию, а не ссылку?

Вопрос или проблема

Итак, я думал, что понимаю, как работают переменные значений и ссылок в C#, но столкнулся с случаем, который неясен и неинтуитивен для меня. Если у меня есть экземпляр класса типа “Assembly” (System.Reflection.Assembly) и я присваиваю его другой переменной, то, похоже, происходит “копирование”, а не передача по ссылке:

var assembly2= assembly1;
assembly1= LoadOtherAssembly();

Console.WriteLine(assembly2);
Console.WriteLine(assembly1);

Очевидно, что на второй строке (assembly1) я получаю другой сборку (что бы ни возвращал LoadOtherAssembly()), но “assembly2” кажется, что содержит оригинальную сборку.

Когда я делаю это с любым другим классом, этого не происходит (как и ожидалось):

public class Person
{
   public string Name;
}

var dave=new Person();
dave.Name="Dave";
var culley=dave;

culley.Name="Culley";

Console.WriteLine(dave.Name);
Console.WriteLine(culley.Name);

В этом случае оба выводят “Culley”, как и ожидалось. Что я упустил, и чем это отличается от первого случая с использованием “Assembly”?

Да, это ошибка в размышлениях, как отмечено в комментариях. Каждый раз, когда я вызываю LoadOtherAssembly(), создается новый объект, и теперь обе переменные указывают на разные “адреса”/”объекты”.

Ответ или решение

В C# важно понимать различие между ссылочными и значимыми типами. Ссылочные типы, такие как классы, хранят ссылки на объекты в памяти, тогда как значимые типы хранят самих объектов. В вашем примере классы Assembly и Person являются ссылочными типами, однако важно рассматривать, что именно происходит при изменении переменной, указывающей на объект.

Когда вы пишете:

var assembly2 = assembly1;
assembly1 = LoadOtherAssembly();

На самом деле вы не "копируете" объект как таковой. Ваша переменная assembly2 получает ссылку на тот же объект, на который указывает assembly1 в момент присвоения. Однако при присваивании assembly1 новой сборки, assembly1 начинает указывать на другой объект, в то время как assembly2 по-прежнему указывает на исходный объект. Это и объясняет, почему assembly2 продолжает содержать ссылку на первоначальный объект сборки.

В случае с классом Person, когда вы выполняете:

var culley = dave;
culley.Name = "Culley";

и затем обращаетесь к dave.Name, вы видите измененное имя, потому что как dave, так и culley ссылаются на один и тот же объект, и, изменяя поле Name через одну ссылку (culley), вы изменяете объект, на который указывают обе переменные.

Таким образом, ключевое различие заключается в том, что в примере с Assembly, когда вы присваиваете assembly1 другую сборку, вы меняете само значение assembly1, а не сам объект, на который ссылается assembly2. В случае с Person обе переменные по-прежнему указывают на один и тот же объект в памяти, и изменение через одну из ссылок изменяет объект для обеих ссылок.

Если бы вы намеренно создавали новый объект Person и присваивали его, тогда вы бы также увидели, что изменения в одной переменной не влияют на другую:

var dave = new Person();
dave.Name = "Dave";
var culley = new Person(); // Создаем новый объект
culley.Name = "Culley";

Console.WriteLine(dave.Name); // Выведет "Dave"
Console.WriteLine(culley.Name); // Выведет "Culley"

Подводя итог, можно сказать, что в случаях, когда вы видите, что переменные "не копируются", скорее всего, это связано с изменением ссылки на объект, а не с самим объектом.

Оцените материал
Добавить комментарий

Капча загружается...