Почему MemberwiseClone определяется в System.Object? - PullRequest
12 голосов
/ 17 июля 2010

Мне интересно, почему MemberwiseClone определяется как защищенный. Это означает, что только производные типы могут получить к нему доступ. В чем проблема, если она была определена как общедоступная?

Ответы [ 3 ]

4 голосов
/ 15 марта 2013
  • Многое не имеет смысла быть клонированным; все, что говорит с неуправляемым дескриптором, например
  • Большинство объектов не нуждаются в клоне
  • Глубокое копирование чего-либо правильно будет действительно сложно, если вы выйдете из нескольких простых случаев
  • Во многих случаях метафоры лучше, чем слепые клоны
  • Ручное добавление клона к нужным вам типам тривиально просто

Тогда для меня нет ничего сложного в том, что не следует добавить в общедоступный API по умолчанию.

4 голосов
/ 10 января 2011

Ответ Павла Минаева из другого обсуждения:

Другие уже объяснили о MemberwiseClone, но никто не объяснил, почему он защищен.Я попытаюсь дать обоснование.

Проблема здесь в том, что MemberwiseClone просто слепо копирует состояние.Во многих случаях это нежелательно.Например, объект может иметь приватное поле, которое является ссылкой на список.Мелкая копия, например, то, что делает MemberwiseClone, приведет к тому, что новый объект будет указывать на тот же список - и класс вполне может быть записан, не ожидая, что список будет доступен кому-либо еще.

Или объект может иметькакое-то поле идентификатора, сгенерированное в конструкторе - опять же, когда вы его клонируете, вы получаете два объекта с одинаковым идентификатором, что может привести к всевозможным странным ошибкам в методах, предполагающих, что идентификатор уникален.

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

Короче говоря, «клонирование» не является четко определенной операцией дляпроизвольные объекты.Тот факт, что для всех классов по умолчанию в C ++ предусмотрен членский оператор operator =, является более неприятным, поскольку слишком часто люди забывают о его наличии и не отключают его для классов, для которых копирование не имеет смысла или опасно.(и таких классов на удивление много).

1 голос
/ 20 января 2011

Если бы MemberwiseClone не существовал, не было бы никаких средств, кроме как с помощью Reflection, для любого наследуемого класса для поддержки операции полиморфного клонирования, за исключением того, что каждый производный класс требовал явного его предоставления.Неспособность производного класса обеспечить операцию клонирования приведет к неожиданному поведению.Например, предположим, что Vehicle, Car и ToyotaCar предоставляют явные методы клонирования, а ToyotaCorolla - нет.Если у кого-то есть объект типа ToyotaCorolla и он пытается его клонировать, получающийся объект будет ToyotaCar.Поскольку существуют ситуации, когда требуется полиморфное клонирование, и было бы неудобно требовать, чтобы каждый производный класс клонируемого класса предоставлял явную поддержку, MemberwiseClone является необходимой частью платформы.

С другой стороны, MemberwiseCloneтакже может быть опасным.Выполнение MemberwiseClone над объектом часто приводит к поломке объекта;попытка использования каких-либо свойств или методов разбитого объекта может привести к повреждению оригинала.

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

Кстати, Microsoft, похоже, считает, что что-то сбивает с толкупротив мелкого клонирования.НетВызов «Clone» для объекта должен клонировать объект на любую глубину, необходимую для получения его определенной семантики.Клонирование FileCabinet (Of T) должно привести к созданию нового FileCabinet, который для целей методов FileCabinet не зависит от оригинала, но должен содержать те же экземпляры T, что и оригинал.Поскольку целью картотеки является хранение экземпляров T, но ничего с ними не делать, клонирование статива не должно подразумевать клонирование содержимого (но это будет означать клонирование любых массивов, которые сам кабинет использует для хранения содержимого).

Кстати, если бы у меня были мои барабанщики, в .Net был бы интерфейс, реализованный с помощью String и примитивных типов (плюс многие другие), называемый DeepClonableIfMutable.При применении к String или другому примитиву метод DeepCloneIfMutable просто возвращает исходный объект.Определенные пользователем неизменяемые объекты могут реализовывать DeepClonableIfMutable, чтобы вести себя аналогично, тогда как изменяемые объекты будут глубоко клонировать себя и любые вложенные экземпляры DeepClonableIfMutable.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...