Je suggérerais de définir une interface ISelf, avec une propriété en lecture seule appelée "Self", de type T (qui, dans toute implémentation, devrait renvoyer "this"). Ensuite, définissez ICloneable qui hérite de ISelf et implémente une méthode, Clone(), de type T.
Ensuite, si vous avez une méthode qui a besoin de quelque chose qui dérive du type Foo et qui est clonable, passez simplement cette méthode à un ICloneable. Pour utiliser l'objet passé en tant que "Foo", accédez à sa propriété "Self". Je suggérerais que les classes avec des méthodes de clonage publiques soient souvent scellées, mais étendent les types non scellés simplement en ajoutant un "wrapper" public "Clone". Cela permettra l'existence de types dérivés qui autorisent ou non le clonage.
Considérez la famille de classes Foo, CloneableFoo, DerivedFoo et CloneableDerivedFoo, et OtherDerivedFoo.
- Foo ne fournit pas de méthode Clone publique; il pourrait être cloné sans difficulté et a une méthode MakeClone protégée.
- CloneableFoo dérive de Foo et expose une méthode Clone publique qui enveloppe MakeClone et implémente ICloneable.
- DerivedFoo est dérivé de Foo; comme Foo, il n'a pas de méthode Clone publique, mais offre une méthode MakeClone protégée.
- CloneableDerivedFoo dérive de DerivedFoo et expose une méthode Clone publique qui enveloppe MakeClone et implémente ICloneable.
- OtherDerivedFoo dérive de DerivedFoo, mais a des invariants de classe qui seraient rompus s'il était cloné ; il masque MakeClone avec une fonction vide taguée obsolète-erreur.
Étant donné ces relations, il serait utile pour une méthode d'accepter tout dérivé clonable de Foo, tandis qu'une autre méthode acceptera tout dérivé - clonable ou non - de DerivedFoo. La première méthode devrait utiliser un paramètre de type ICloneable, tandis que la seconde prend un paramètre de type DerivedFoo. Notez que si DerivedFoo était dérivé de CloneableFoo plutôt que de Foo, il ne serait pas possible d'avoir quelque chose dérivant de DerivedFoo sans promettre une méthode Clone publique.