:: Не фоксом единым
Копирование
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Есть код:

public class Test
{
public string Name;
public Test Copy ()
{
return new Test()
{
Name = Name // Name = string.Copy(Name)
};
}
}
class Program
{
static void Main(string[] args)
{
var a = new Test() { Name = "1" };
var b = a.Copy();
b.Name = "2"; // тут как то меняем
Console.WriteLine(a.Name); // выведет 1
Console.ReadLine();
}
}

У объекта есть метод Copy() который создаёт копию объекта. Копия ни как не должна быть связана с первоначальным объектом. Т.е. изменение копии не должно повлиять на первоначальный объект. Между народом возникли разногласия. Некоторые говорят, что надо делать не Name = Name непременно Name = string.Copy(Name). Теоретически, b.Name - это ведь ссылка на строку. Значит, можно изменить сроку без изменения ссылки. Другие говорят - нет такого кода, который можно поставить вместо b.Name="2", что бы вывелось 1.

Какие будут мнения? Кто прав?
Ratings: 0 negative/0 positive
Re: Копирование
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
Тут есть про глубокое и поверхностное клонирование.
docs.microsoft.com
При этом использование данного метода здорово упрощает и сокаращает код - уже не надо в своём методе копирования (если оно должно быть "глубоким") перечислять все 100500 свойств объекта - достаточно озаботится созданием "настоящих копий" лишь для свойств ссылочных типов.

И хотя в примере применяют String.Copy(Name) это действие на 99% бессмысленное. Да, между
string newString = oldString;
и
string newString = String.Copy(oldString);
есть разница - она проявится при использовании метода ReferenceEquals. Ну и ещё (теоретически) при использовании небезопасного кода - по идее там можно поменять содержимое строки не поменяв саму ссылку на неё (ну и, конечно, если залезть непосредственно в память дотнет-процесса то тоже можно поменять содержимое строки). Правда за такие выкрутасы надо бить по голове автора до просветления Это нарушает сам принцип неизменности дотнетовских строк (строка хоть и сылочный тип, но ведёт себя во многом как value тип). Ну и в современной версии CLR метод String.Copy помечен как Obsolete - так что использовать его всё же не следует.

Кстати, есть штатный интерфейс ICloneable с методом Clone предназначенный именно для целей созданий копий - при этом НЕ регламентируется какую именно копию будет создавать каждая конкретная реализация - глубокую, поверхностную или что-то среднее (ну там одни типы или даже просто свойства "глубоко" копировать, а другие - брать ссылку на исходный объект). Правда мануал не рекомендует использовать этот интерфейс в качестве публичного (т.е. не стоит его объявлять и соответственно реализовывать для публично видимых объектов - именно по причине неопределённости поведения). Кроме того он несколько неудобен, т.к. возвращает всегда object - т.е. потребуется приведение типа. Если уж есть большая нужда (во многих типах) в унифицированной операции копирования, то лучше свой generic интерфейс описать и его и реализовывать.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Копирование
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Ну и ещё (теоретически) при использовании небезопасного кода - по идее там можно поменять содержимое строки не поменяв саму ссылку на неё (ну и, конечно, если залезть непосредственно в память дотнет-процесса то тоже можно поменять содержимое строки).
Т.е. из Managed кода изменить строку не получится.
Ratings: 0 negative/0 positive
Re: Копирование
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
Тут речь идёт про небезопасный код, а не про неуправляемый.
Старая, но полезная статья.
habr.com


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Копирование
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Т.е. из unsafe кода таки можно. Спасибо.
Ratings: 0 negative/0 positive
Re: Копирование
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
"Можно" в смысле технической возможности - но если у вас есть идиот странный человек который так будет делать без ну очень веской причины (я таковую сходу придумать не могу - тем более для бизнес-объектов, не в части взаимодействия со всякими неуправляемыми кодами, низкоуровневыми системными АПИ, и т.п.), то лучше сразу гнать взашей Соответственно строить всю логику исходя из того что кто-то там сделает этакое - неправильно. Тем более что незапланированное "синхронное" изменение содержимого строкового поля в объекте-копии, это просто детский лепет по сравнению с другими весёлостями которые ожидают, если таки нарушить принцип неизменности значений строкового типа. Принцип этот чётко прописан в мануалах, и адекватный разработчик в общем то не будет подозревать что кто-то в здравом уме станет его нарушать Тем паче что даже сами разработчики системы пометили String.Copy как устаревший, и поправили все те места в CLR где это использовалось


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Копирование
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
В настоящий момент в проекте unsafe не встречается. Так что, опасности нет. Если кто то попытается вставить в код unsafe, ему придётся объяснять - зачем (как говорят индейцы, магическое слово НАХУА).
Ratings: 0 negative/0 positive
Re: Копирование
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
Тут дело даже не в unsafe как таковом - его использование то не вызывает вопросов, а в том зачем из строки, прописанной во всех мануалах как неизменная сущность, делать изменяемую сущность Ну это как хакнуть рантайм чтобы false стало истинным, а true ложным


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Копирование
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
Первоначальный спор между коллегами был на тему:

в public Test Copy() нужен ли Name = string.Copy(Name) или достаточно Name = Name.

Судя по тому, что без unsafe изменить b.Name не удастся, достаточно Name = Name. Но, если бы мы писали какую то библиотеку (и не имели бы контроля надо кодом, который использует b.Name, string.Copy нужен.



Исправлено 1 раз(а). Последнее : S-type, 06.06.19 08:10
Ratings: 0 negative/0 positive
Re: Копирование
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
Не нужен уже хотя бы потому что это obsolete метод в текущей версии. Сами разработчики CLR от него избавляются.
А сколько "веселья" можно получить если начать изменять значения в объектах string... Тривиальнейший пример даже в мануале есть:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
MoronsMethod();
Console.WriteLine("Hello World!");
}
private static void MoronsMethod()
{
var str = "Hello World!";
unsafe
{
fixed (char* p = str)
{
p[0] = 'E';
p[1] = 'n';
p[2] = 'd';
p[3] = ' ';
p[4] = 'o';
p[5] = 'f';
}
}
}
}


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Копирование
S-type

Сообщений: 2969
Дата регистрации: 24.04.2004
М, да... Т.е. компилятор экономит память - собирает литералы "в кучку", меняем один - меняется другой. Просто звездец.
Ratings: 0 negative/0 positive
Re: Копирование
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
Звиздец это не уча матчасть "лепить горбатого" - в т.ч. делать из string "изменяемый" тип, ну или "предполагать" что string это изменяемый тип и "защищаться" путём клонирования строк (так то и шпагу глотать можно - но успешно это может проделать лишь 1 из 100000 человек ). А интернирование строк - полезный и хорошо документированный механизм, он и в рантайме доступен, не только для строковых литералов (т.е. при компиляции).


------------------
WBR, Igor
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 7 (Гостей: 7)

© 2000-2024 Fox Club 
Яндекс.Метрика