One "feature" of Java is that there's really only one non-primitive type: an object reference, which may be used in all sorts of ways. While that makes the framework easy to implement, it means that the type of a variable is insufficient to describe its meaning. While .net improves on Java in many ways, it shares that fundamental weakness.
For example, suppose an object George
has a field Bob
of type IList<String>
[or, for Java, list<string>
]. There are at least five fundamentally different things such a field could represent:
- It holds a reference to an object holding a set of strings to which it will never allow any changes. If item #5 of that list is "Barney", then item #5 on that list will never be anything other than "Barney". In this scenario, `Bob` encapsulates only immutable aspects of the list. Further, the reference may be freely shared to any code that's interested in that aspect of George's state.
- It holds a reference to an object holding a set of strings which may be modified by anyone holding a reference, but no entity with a reference to that object will modify the list nor allow it to be exposed to anything that might do so. In other worse, while the list would allow its contents to be changed, nothing will in fact ever alter those contents. As above, `Bob` encapsulates only immutable aspects of the list, but `George` is responsible for maintaining such immutability by exposing the reference only to code that can be trusted not to modify the list.
- It holds the only reference, anywhere in the universe, to an object holding a set of strings which it modifies at will. In this scenario, `Bob` encapsulates the *mutable state* of the list. If one copies `George`, one must make a new list with the same items as the old, and give the copy a reference to that. Note also that `George` cannot pass a reference to any code that might persist the reference, whether or not that code would try to modify the list.
- It holds a reference to a list which is "owned" by some other object, which will be used either to add items to the list for the other object's benefit, or to observe things the other object has put in the list for `George`'s benefit. In this scenario, `Bob` encapsulates the *identity* of the list. In a correct clone, `Bob` must identify the *same list* as in the original.
- It holds a reference to a list which it owns, and which will be mutated, but to which some other objects also hold a reference (perhaps so they can add things to the list for `George`'s benefit, or perhaps so they can see things `George` does with the list). In this scenario, `Bob` encapsulates *both mutable state and identity*. The existence of a field which encapsulates both aspects means that *it is not possible to make a semantically-correct copy of `George` without the cooperation of other objects*.
In short, it's possible for Bob
to encapsulate the list's mutable state, its identity, both, or neither (immutable state, other than identity, is a 'freebie'). If it encapsulates only mutable state, a semantically-correct copy of George
must have Bob
reference a different list which is initialized with the same contents. If it encapsulates only identity, a semantically-correct copy must have Bob
reference the same list. If it encapsulates both mutable state and immutble state, George
cannot be properly cloned in isolation. Fields that do neither may be copied or not, as convenient.
If one can properly determine which fields encapsulate the referenced objects' mutable states, which ones encapsulate identity, and which ones both, it will be obvious what a semantically-correct cloning operation should do. Unfortunately, there's no standard convention in the Framework for categorizing fields in such fashion, so you'll have to come up with your own method and then a cloning scheme that uses it.