Should I provide a deep clone when implementing ICloneable?

前端 未结 3 1052
终归单人心
终归单人心 2021-01-12 23:51

It is unclear to me from the MSDN documentation if I should provide a deep or a shallow clone when implementing ICloneable. What is the preferred option?

3条回答
  •  囚心锁ツ
    2021-01-13 00:10

    Given the way an object is defined, there shouldn't be any question about "deep cloning" versus "shallow cloning". If an object encapsulates the identities of things, a clone of the object should encapsulate the identities of the same things. If an object encapsulates the values of mutable objects, a copy should encapsulate detached mutable objects holding the same values.

    Unfortunately, neither .NET or Java includes in the type system whether references are held to encapsulate identity, mutable value, both, or neither. Instead, they just use a single reference type and figure that code which owns the only copy of a reference, or owns the only reference to a container which holds the only copy of that reference, may use that reference to encapsulate either value or state. Such thinking might be tolerable for individual objects, but poses real problems when it comes to things like copying and equality testing operations.

    If a class has a field Foo which encapsulates the state of a List which is to encapsulate the identities of objects therein, and may in future encapsulate different objects' identities, then a clone of the Foo should hold a reference to a new list which identifies the same objects. If the List is used to encapsulate the mutable states of the objects, then a clone should have a reference to a new list which identifies new objects that have the same state.

    If objects included separate "equivalent" and "equals" methods, with hashcodes for each, and if for each heap object type there were reference types that were denoted as encapsulating identity, mutable state, both, or neither, then 99% of equality testing and cloning methods could be handled automatically. Two aggregates are equal if all components which encapsulate identity or mutable state are equivalent (not merely equal) and those that encapsulate neither are at least equal; two aggregates are equivalent only if all corresponding components are and always will be equivalent [this often implies reference equality, but not always]. Copying an aggregation requires making a detached copy of each constituent that encapsulates mutable state, copying the reference to each constituent that encapsulates identity, and doing either of the above for those which encapsulates neither; an aggregation with a constituent which encapsulates both mutable state and identity cannot be cloned simply.

    There are a few tricky cases that such rules for cloning, equality, and equivalence wouldn't handle properly, but if there were a convention to distinguish a List from a List, and to support both "equivalent" and "equals" tests, 99% of objects could have Clone, Equals, Equivalent, EqualityHash, and EquivalenceHash auto-generated and work correctly.

提交回复
热议问题