Pouvez-vous m'expliquer pourquoi je dois hériter de ICloneable
et implémenter la méthode Clone()
?
Si je veux faire une copie complète, ne puis-je pas simplement implémenter ma méthode? Disons que MyClone()
?
Pourquoi devrais-je hériter de ICloneable
? Quels sont les avantages? S'agit-il simplement de rendre le code "plus lisible"?
Tu ne devrais pas. Microsoft recommande de ne pas implémenter ICloneable
car il n'y a aucune indication claire de l'interface si votre méthode Clone
effectue un clone "profond" ou "superficiel".
Voir cet article de blog de Brad Abrams en 2003 (!) Pour plus d'informations.
L'interface ICloneable
par lui-même n'est pas très utile, c'est-à-dire qu'il n'y a vraiment pas beaucoup de situations où il est utile de savoir qu'un objet est clonable sans en savoir autre chose. Il s'agit d'une situation très différente, par exemple, IEnumerable
ou IDisposable
; il existe de nombreuses situations où il est utile d'accepter un IEnumerable
sans savoir autre chose que comment l'énumérer.
D'un autre côté, ICloneable
peut être utile lorsqu'il est appliqué en tant que contrainte générique avec d'autres contraintes. Par exemple, une classe de base pourrait utilement prendre en charge un certain nombre de dérivés, dont certains pourraient être utilement clonés et d'autres non. Si le type de base lui-même exposait une interface de clonage publique, alors tout type dérivé qui ne pourrait pas être cloné violerait le principe de substitution de Liskov. Pour éviter ce problème, le clonage prend en charge le type de base à l'aide d'une méthode protégée et autorise les types dérivés à implémenter une interface de clonage publique comme bon leur semble.
Une fois cela fait, une méthode qui veut accepter un objet de type WonderfulBase
, et doit pouvoir le cloner, pourrait être codée pour accepter un objet WonderfulBase qui prend en charge le clonage (en utilisant un paramètre de type générique avec type de base et ICloneable
contraintes). Bien que l'interface ICloneable
n'indique pas elle-même un clonage profond ou superficiel, la documentation de WonderfulBase
indiquerait si le clonable WonderfulBase
doit être cloné en profondeur ou en superficiel. Essentiellement, l'interface ICloneable
n'accomplirait rien qui ne serait pas accompli en définissant ICloneableWonderfulBase
, sauf qu'elle éviterait d'avoir à définir des noms différents pour chaque classe de base clonable différente.
ICloneable
est l'un de ces artefacts de la BCL qui a été controversé. Il n'y a aucune vraie raison à mon humble avis de le mettre en œuvre. Cela dit, si je vais créer une méthode de clonage, j'implémente ICloneable
et je fournis ma propre version typée forte de Clone
.
Le problème avec ICloneable
est qu'il n'est jamais indiqué si Clone
était une copie superficielle ou profonde, ce qui est très différent. Le fait qu'il n'y ait pas de ICloneable<T>
pourrait être une indication des réflexions de Microsoft sur ICloneable
Matt a raison, ne l'utilisez pas. Créez votre propre méthode Copy()
(ou un nom similaire) et indiquez parfaitement clair dans votre API publique, que votre méthode crée une copie profonde ou superficielle de votre objet.