En C#, quelle est la meilleure façon d'ajouter la fonctionnalité de copie (profonde) à une classe ? Doit-on implémenter le constructeur de copie, ou plutôt dériver de ICloneable et implémenter la méthode Clone() ?
Le problème avec ICloneable
est, comme d'autres l'ont mentionné, qu'il ne précise pas s'il s'agit d'une copie profonde ou superficielle, ce qui le rend pratiquement inutilisable et, en pratique, rarement utilisé. Il renvoie également object
ce qui est pénible, car cela nécessite beaucoup de casting. (Et bien que vous ayez spécifiquement mentionné les classes dans la question, l'implémentation de ICloneable
sur un struct
nécessite de la boxe).
Un constucteur de copie souffre également de l'un des problèmes de ICloneable. Il n'est pas évident de savoir si un constructeur de copie effectue une copie profonde ou superficielle.
Account clonedAccount = new Account(currentAccount); // Deep or shallow?
Il serait préférable de créer une méthode DeepClone(). De cette façon, l'intention est parfaitement claire.
Cela soulève la question de savoir s'il doit s'agir d'une méthode statique ou d'une méthode d'instance.
Account clonedAccount = currentAccount.DeepClone(); // instance method
o
Account clonedAccount = Account.DeepClone(currentAccount); // static method
Je préfère parfois légèrement la version statique, simplement parce que le clonage semble être quelque chose qui est fait à un objet plutôt que quelque chose que l'objet fait. Dans un cas comme dans l'autre, le clonage d'objets faisant partie d'une hiérarchie d'héritage pose des problèmes, et la façon dont ces problèmes sont résolus peut finalement déterminer la conception.
class CheckingAccount : Account
{
CheckAuthorizationScheme checkAuthorizationScheme;
public override Account DeepClone()
{
CheckingAccount clone = new CheckingAccount();
DeepCloneFields(clone);
return clone;
}
protected override void DeepCloneFields(Account clone)
{
base.DeepCloneFields(clone);
((CheckingAccount)clone).checkAuthorizationScheme = this.checkAuthorizationScheme.DeepClone();
}
}