Me pregunto por qué MemberwiseClone se define como protegido. Esto significa que solo los tipos derivados pueden acceder a él. ¿Cuál es el problema si se definió como público?¿Por qué se define MemberwiseClone en System.Object?
Respuesta
Pavel Minaev's answer from another discussion:
Otros ya han explicado sobre MemberwiseClone, pero nadie dio la explicación de por qué está protegido. Trataré de dar el razonamiento.
El problema aquí es que MemberwiseClone simplemente copia ciegamente el estado. En muchos casos, esto es indeseable. Por ejemplo, el objeto puede tener un campo privado que es una referencia a una Lista. Una copia superficial, como lo que hace MemberwiseClone, daría como resultado un nuevo objeto que apunta a la misma lista, y la clase podría escribirse sin esperar que la lista se comparta con nadie más.
O un objeto puede tener algún tipo de campo ID, generado en el constructor; de nuevo, cuando lo clona, obtiene dos objetos con la misma ID, lo que puede dar lugar a todo tipo de fallas extrañas asumiendo que ID es único.
O supongamos que tiene un objeto que abre un socket o una secuencia de archivos, y almacena una referencia a eso. MemberwiseClone solo copiará la referencia, y puede imaginarse que dos objetos que intentan intercalar llamadas al mismo flujo no terminarán bien.
En resumen, "clonación" no es una operación bien definida para objetos arbitrarios. El hecho de que memberwise operator = se proporcione para todas las clases de forma predeterminada en C++ es más una molestia, ya que con demasiada frecuencia las personas olvidan que está allí y no lo desactivan para las clases para las que copiar no tiene sentido, o es peligroso (y sorprendentemente hay muchas clases similares).
Si MemberwiseClone no existiera, no habría otro medio, salvo el uso de Reflection, para que una clase heredable sea compatible con una operación de clonación polimórfica, excepto que requiera que cada clase derivada proporcione explícitamente una. La falla de una clase derivada para proporcionar una operación de clonación resultaría en un comportamiento inesperado. Por ejemplo, suponga que Vehicle, Car y ToyotaCar proporcionan métodos de clonación explícitos, pero ToyotaCorolla no. Si alguien tiene un objeto de tipo Toyota Corolla e intenta clonarlo, el objeto resultante sería un ToyotaCar. Dado que hay situaciones en las que se requiere la clonación polimórfica, y sería inconveniente requerir que cada clase derivada de una clase clonable brinde apoyo explícito, MemberwiseClone es una parte necesaria del marco.
Por otro lado, MemberwiseClone también puede ser peligroso. Realizar un MemberwiseClone en un objeto con frecuencia producirá un objeto roto; intentar usar cualquier propiedad o método del objeto roto puede dañar el original.
Es una pena que Microsoft no defina mejor una buena práctica para la clonación. Es posible, y no excesivamente difícil, diseñar un patrón de clonación polimórfica que no requiera que las clases heredadas hagan nada explícitamente a menos que agreguen campos que requieren un manejo especial, o a menos que un llamante espere que el tipo de retorno declarado del método Clone sea la clase derivada. Si bien la última situación con frecuencia será un requisito, la falla al implementar explícitamente el método necesario producirá un error en tiempo de compilación, en lugar de un comportamiento defectuoso en tiempo de ejecución.
Por cierto, Microsoft parece pensar que hay algo confuso acerca de la clonación profunda frente a la superficial. No hay Llamar a "Clonar" en un objeto debe clonar el objeto a la profundidad que sea necesaria para obtener su semántica definida. La clonación de un FileCabinet (Of T) debería producir un nuevo FileCabinet que, a los fines de los métodos de FileCabinet, es independiente del original, pero debe contener las mismas instancias de T que el original.Dado que el propósito de un archivador es contener instancias de T, pero no hacer nada con ellas, clonar el gabinete no debe implicar la clonación del contenido (pero implicaría clonar cualquier arreglo que el propio Gabinete use para contener los contenidos).
Por cierto, si tuviera mi druthers, habría una interfaz en .Net, implementada por String y tipos primitivos (y muchos otros), llamada DeepClonableIfMutable. Cuando se aplica a una Cadena u otra primitiva, el método DeepCloneIfMutable simplemente devolvería el objeto original. Los objetos inmutables definidos por el usuario podrían implementar DeepClonableIfMutable para que se comporte de manera similar, mientras que los objetos mutables se clonarían a fondo ellos mismos y cualquier instancia DeepClonableIfMutable anidada.
- Muchas cosas no tienen sentido para clonar; cualquier cosa que habla con un mango no administrado, por ejemplo
- mayoría de los objetos no necesitan una instalación clon
- -copia completa algo adecuadamente es realmente difícil si vas fuera de algunos casos simples
- en muchos casos, hay mejores metáforas que los clones ciegos
- adición manual de una instalación clon a sus tipos que lo necesitan es trivialmente fácil
Para mí, entonces, es una obviedad que esto debería no se agregará a la API pública de forma predeterminada.
- 1. ¿Por qué no se define Element.prototype?
- 2. ¿Por qué System.Version en .NET se define como Major.Minor.Build.Revision?
- 3. ¿Por qué la macro 'max' se define así en C?
- 4. ¿Por qué se define foldl de forma extraña en Racket?
- 5. Cómo fundido System.Object [*] para System.Object []
- 6. ¿Cómo puedo llamar a MemberwiseClone()?
- 7. boxeo y unboxing, ¿por qué las salidas no son "System.Object"?
- 8. ¿Por qué no se define JavaScript RegExp/^ \ w + $/match?
- 9. ¿Por qué se define este búfer dentro de un bucle?
- 10. C#: ¿En qué ensamblado se define SHDocVw.WebBrowser_V1?
- 11. ¿Por qué este código no se define pero no 2?
- 12. .Net MemberwiseClone vs Java Clone
- 13. ¿Por qué SDL define la macro principal?
- 14. Linq Query sigue lanzando "No se puede crear un valor constante de tipo System.Object ....", ¿Por qué?
- 15. ¿Para qué propiedad interna se define ECMAScript?
- 16. ¿Por qué Iterator define la operación remove()?
- 17. ((System.Object) p == null)
- 18. $ excepción se define en "locales"
- 19. ¿Cómo se define (?) Internamente?
- 20. ¿Por qué var evalúa a System.Object en "foreach (var row in table.Rows)"?
- 21. abstractmethod no se define
- 22. ¿Qué significa ## en a #define?
- 23. ¿Qué define esta macro?
- 24. ¿Por qué cada clase en .Net deriva de System.Object? ¿Cuales son los beneficios?
- 25. ¿Cómo saber en qué biblioteca se define una función específica?
- 26. ¿Cómo se define threadsafe?
- 27. ¿Cuál es el método que hace MemberwiseClone()?
- 28. ¿Cómo se usa #define?
- 29. ¿Por qué #ifndef y #define se usan en archivos de encabezado C++?
- 30. ¿Por qué #define no requiere un punto y coma?