Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

C# - быстро склонировать несложный объект

2158  1 2 3 4 все
alex445 коренной житель08.10.23 19:54
08.10.23 19:54 

Есть один или пачка POCO, пусть даже с какой-то иерархией наследования. Какой способ быстро склонировать эту пачку в наше время?


Раньше народ клепал свои методы на каждый такой класс. Но это надо не забыть исправить такой метод, если исправляется какое-то свойство в клонируемом типе. Да и больше подходит для кастомного копирования с изменениями (т.е. это уже не копирование, а сериализация будет), а не для простого "один к одному".


Потом варианты через сериализаторы - если не сотни мегабайт объектов так клонировать, то пойдёт. Особенно, если не нужно расставлять атрибуты сериализации - т.е. подойдут всякие JSON-сериализаторы.


Ещё с деревьями выражений находил примеры. Но они какие-то замудрёные. Хотя и говорят, что это быстрее всего.


Есть ещё разные фреймворки, но по-моему они внутри делают что-то из вышеперечисленного.


Тут чел собрал разные методы, при этом топит за ручное клонирование. Но то 2012 год. Да и уже говорил, что это скорее для сложного клонирования не "один к одному" и разных не-POCO вещей.


С сериализаторами просто - Serialize, Deserialize, и вот у тебя полная копия POCO. Собственно, сейчас с ними клонирую.

#1 
Программист коренной житель09.10.23 08:03
NEW 09.10.23 08:03 
в ответ alex445 08.10.23 19:54

В шарпе есть IClonable. Так вот все объекты, которые надо клонировать наследуешь от этого интерфейся и дело в шляпе.


Чтобы не забыть клонировать новые поля можно написать юнит-тест и рефлекшенами считать количество (и названия) полей. Этот прием также можно использовать для тестирования Equal.

#2 
alex445 коренной житель09.10.23 11:21
NEW 09.10.23 11:21 
в ответ Программист 09.10.23 08:03, Последний раз изменено 09.10.23 11:24 (alex445)
В шарпе есть IClonable.

Который делает примерно ничего, кроме объявления контракта, что тут что-то клонируется - всё должен делать ты сам, причём ручками. Мне-то надо, чтобы работать поменьше, а результата побольше.


Чтобы не забыть клонировать новые поля можно написать юнит-тест и рефлекшенами считать количество (и названия) полей. Этот прием также можно использовать для тестирования Equal.

Что-то невероятно замудрённое. ))


Короче, продолжаю юзать это - не нужно никаких атрибутов дописывать, интерфейсы реализовывать, и вообще ничего не нужно - тупо на любой POCO класс применяется из коробки:

var temp = JsonConvert.SerializeObject(original);

var copy = JsonConvert.DeserializeObject(temp);

#3 
Срыв покровов патриот09.10.23 23:06
NEW 09.10.23 23:06 
в ответ Программист 09.10.23 08:03
В шарпе есть IClonable. Так вот все объекты, которые надо клонировать наследуешь от этого интерфейся и дело в шляпе.

вот это ты смачно в лужу пукнул.

#4 
Срыв покровов патриот09.10.23 23:08
NEW 09.10.23 23:08 
в ответ alex445 09.10.23 11:21, Последний раз изменено 09.10.23 23:08 (Срыв покровов)
Короче, продолжаю юзать это - не нужно никаких атрибутов дописывать, интерфейсы реализовывать, и вообще ничего не нужно - тупо на любой POCO класс применяется из коробки:

Как оно с private свойствами работает?

Падает ли, если в дереве объектов окажется циклическая зависимость?

#5 
AlexNek патриот09.10.23 23:34
AlexNek
NEW 09.10.23 23:34 
в ответ alex445 08.10.23 19:54
alex445 коренной житель10.10.23 00:00
NEW 10.10.23 00:00 
в ответ Срыв покровов 09.10.23 23:08, Последний раз изменено 10.10.23 00:05 (alex445)
Как оно с private свойствами работает?
Падает ли, если в дереве объектов окажется циклическая зависимость?

Для приватных надо атрибуты расставлять. Или настройки для всего типа делать (т.е. тоже атрибут).

Цикл можно заигнорить.

Другой объект в составе сериализуемого можно сериализовать со всеми его данными, а можно лишь ссылку на него.

#7 
Срыв покровов патриот10.10.23 06:55
NEW 10.10.23 06:55 
в ответ alex445 10.10.23 00:00

короче нет серебряной пули (((

Плюс у тебя во второй ссылке реестр идёт про библиотеку Newtonsoft

#8 
Программист коренной житель10.10.23 08:27
NEW 10.10.23 08:27 
в ответ Срыв покровов 09.10.23 23:06
вот это ты смачно в лужу пукнул.

IClonable и был придуман для того, что хочет Алекс.

Никто кроме самого объекта не может знать как надо клонироваться (и надо ли вообще). Так что правильный путь - реализация IClonable. Все остальное - костыли, которые посыпятся в самый неподходящий момент.

#9 
alex445 коренной житель10.10.23 09:24
NEW 10.10.23 09:24 
в ответ Срыв покровов 10.10.23 06:55, Последний раз изменено 10.10.23 09:33 (alex445)
короче нет серебряной пули (((
Плюс у тебя во второй ссылке реестр идёт про библиотеку Newtonsoft

Конечно пулит нет. Я же упростил и говорил про POCO.


Эту либу я и раньше юзал. МСовская была не очень раньше. Они её дорабатывают, но всё равно не дотягивает до json.net. Но суть та же - клонирование несложных объектов через сериализацию до сих пор самый простой способ клонирования, чем вводить свои копировщики, интерфейсы и прочее. Если будете свои копировщики вводить, то столкнётесь с теми же проблемами, что и при сериализации - как ссылки обрабатывать, как циклические зависимости и прочее. И придёте к тем же решениям - вводить нотацию для ссылок или копировать как есть с дублированием данных, опция для игнора циклов, и т.п. Только сами вы это будете неделями и месяцами разрабатывать со всеми сопустствующими ошибками. А сериализаторы уже готовы и отлажены. Проще добить свои классы до сериализации (расставить атрибуты) и воспользоваться ей, чем вводить свои копировщики.


IClonable - старый дотнетовский интерфейс, введённый ещё до появления других удобных инструментов клонирования. Он никак не помогает клонировать, т.к. не содержит никаких вспомогательных инструментов, а просто декларация, широко используемая в самом Дотнете. Написать интерфейс клонирования с одним едиственным методом без реализации - что может быть проще. А вот реализовать... Атавизм, как и класс HashTable и многие другие, оставленные для совместимости.

#10 
alex445 коренной житель10.10.23 09:41
NEW 10.10.23 09:41 
в ответ Программист 10.10.23 08:27, Последний раз изменено 10.10.23 09:42 (alex445)
вот это ты смачно в лужу пукнул.
IClonable и был придуман для того, что хочет Алекс.
Никто кроме самого объекта не может знать как надо клонироваться (и надо ли вообще). Так что правильный путь - реализация IClonable. Все остальное - костыли, которые посыпятся в самый неподходящий момент.

С интерфейсом проблема в том, что он декларирует наличие реализации, но никак не отслеживает её актуальность при изменении типа. Тип изменился, и разработчик должен посмотреть, какие другие части этого типа тоже должны измениться. Со сложными типами это море работы, и всё равно можно что-то упустить. Тогда как атрибуты находятся там же, где и изменяющиеся вещи в типе - прямо над ними. Так что забыть изменить сериализацию сложнее - это надо специально атрибуты игнорировать.


Предлагают обложиться тестами, ага. Только как в тестах отслеживать, что там теперь должны быть новые члены? Создавать тестовые объекты через рефлексию, проходя по всем текущим свойствам и сравнивая с объектом после сериализации? Вы тогда тесты будете разрабатывать дольше, чем сами типы, а их сложность может потребовать тесты над тестами. А по заветам отцов-основателей, тесты должны быть максимально простыми.

#11 
MrSanders коренной житель10.10.23 10:40
NEW 10.10.23 10:40 
в ответ Программист 10.10.23 08:27
Так что правильный путь - реализация IClonable. Все остальное - костыли, которые посыпятся в самый неподходящий момент.

+1. И "копирующий конструктор".

#12 
Murr патриот10.10.23 11:56
Murr
NEW 10.10.23 11:56 
в ответ MrSanders 10.10.23 10:40

И "копирующий конструктор".

-----

В С++ - да.

В С# - уже нет.


Насколько Я помню среда .НЕТа пользует IClonable по своему усмотрению, а про "копирующий конструктор" она не в курсе.

#13 
Срыв покровов патриот10.10.23 13:47
NEW 10.10.23 13:47 
в ответ Murr 10.10.23 11:56

Кто чем у тебя пользуется?

#14 
alex445 коренной житель10.10.23 16:16
NEW 10.10.23 16:16 
в ответ Срыв покровов 10.10.23 13:47, Последний раз изменено 10.10.23 16:20 (alex445)

Посмотрите на количество имеющих этот интерфейс внутренних классов Дотнета (список "Derived") -

https://learn.microsoft.com/en-us/dotnet/api/system.iclone...

Все они юзают его, а не какой-то конструктор-копировщик. Последний - действительно пришёл из плюсов.


Этот интерфейс можно использовать, если у вас какая-то сложная схема копирования объектов, требующая логики реализации, которую нельзя просто атрибутами обозначить. Ну и если хотите синхронизироваться с другими системами, которые на этот интерфейс рассчитывают. А мне для простых объектов неохота ничего писать, а охота как можно быстрее. А уж если эти объекты и так должны сериализироваться - т.е. я их для этого уже подготовил - то тем более грех не воспользоваться уже готовым инструментом.

#15 
Срыв покровов патриот10.10.23 17:35
NEW 10.10.23 17:35 
в ответ alex445 10.10.23 09:24
Конечно пулит нет. Я же упростил и говорил про POCO.

а это все ещё POCO


#16 
alex445 коренной житель10.10.23 23:02
NEW 10.10.23 23:02 
в ответ Срыв покровов 10.10.23 17:35

И что, не сериализируется?

#17 
Срыв покровов патриот11.10.23 12:14
NEW 11.10.23 12:14 
в ответ alex445 10.10.23 23:02

предположу, что нет.

По WCF точно не передаётся, если присутствует циклическая зависимость.

#18 
alex445 коренной житель11.10.23 13:38
NEW 11.10.23 13:38 
в ответ Срыв покровов 11.10.23 12:14

Тогда либо игнорить циклы, либо настраивать модели, расставляя атрибуты, чтобы часть полей не сериализовывалась. Но это уже не просто вызвать пару методов для клонирования.

#19 
Срыв покровов патриот11.10.23 13:48
NEW 11.10.23 13:48 
в ответ alex445 11.10.23 13:38

если часть полей не клонируется, то это уже не клонирование.

#20 
1 2 3 4 все