Dlaczego należy zaimplementować ICloneable w języku C #?

111

Czy możesz mi wyjaśnić, dlaczego powinienem dziedziczyć ICloneable i wdrożyć tę Clone()metodę?

Jeśli chcę zrobić dokładną kopię, czy nie mogę po prostu wdrożyć mojej metody? PowiedzmyMyClone() ?

Dlaczego powinienem dziedziczyć po ICloneable? Jakie są zalety? Czy to tylko kwestia uczynienia kodu bardziej czytelnym?

uinc
źródło

Odpowiedzi:

117

Nie powinieneś. Firma Microsoft odradza implementację, ICloneableponieważ w interfejsie nie ma wyraźnego wskazania, czy Clonemetoda wykonuje „głęboki”, czy „płytki” klon.

Zobacz ten post na blogu Brada Abramsa z 2003 roku (!), Aby uzyskać więcej informacji.

Matt Hamilton
źródło
4
Wayback link do artykułu, który jest teraz 404: web.archive.org/web/20040419170407/http://blogs.msdn.com/brada/ ...
harpo
2
Lepszy link: blogs.msdn.microsoft.com/brada/2004/05/03/…
Eric Lippert
29

ICloneableInterfejs sama nie jest bardzo użyteczne, to znaczy, że tak naprawdę nie jest wiele sytuacji, w których warto jest wiedzieć, że obiekt jest Cloneable nie wiedząc niczego o nim. To jest sytuacja zupełnie inna niż np. IEnumerableLub IDisposable; jest wiele sytuacji, w których warto zaakceptować coś, IEnumerablenie wiedząc nic poza tym, jak je wyliczyć.

Z drugiej strony ICloneablemoże być przydatne, gdy jest stosowane jako ograniczenie ogólne wraz z innymi ograniczeniami. Na przykład klasa bazowa może z pożytkiem obsługiwać wiele pochodnych, z których niektóre można pożytecznie sklonować, a inne nie. Jeśli sam typ bazowy ujawniłby publiczny interfejs klonowania, to każdy typ pochodny, którego nie można było sklonować, naruszyłby zasadę zastępowania Liskova. Sposobem na uniknięcie tego problemu jest umożliwienie klonowania typu podstawowego przy użyciu metody chronionej i zezwolenie typom pochodnym na implementację publicznego interfejsu klonowania według własnego uznania.

Po wykonaniu tej czynności metoda, która chce zaakceptować obiekt WonderfulBasetypu i musi być w stanie go sklonować, mogłaby zostać zakodowana tak, aby akceptowała obiekt WonderfulBase obsługujący klonowanie (przy użyciu parametru typu ogólnego z typem bazowym i ICloneableograniczeniami) . Chociaż sam ICloneableinterfejs nie wskazywałby na głębokie lub płytkie klonowanie, dokumentacja WonderfulBasewskazywałaby, czy klonowalny WonderfulBasepowinien być klonowany głęboko, czy płytko. Zasadniczo ICloneableinterfejs nie osiągnąłby niczego, czego nie dałoby się osiągnąć poprzez zdefiniowanie ICloneableWonderfulBase, poza tym, że uniknąłby konieczności definiowania różnych nazw dla każdej innej możliwej do klonowania klasy bazowej.

supercat
źródło
18

ICloneablejest jednym z tych artefaktów w BCL, który był kontrowersyjny. Nie ma prawdziwego powodu IMHO, aby to wdrożyć. Mając to na uwadze, jeśli mam zamiar utworzyć metodę klonowania, implementuję ją ICloneablei udostępniam własną silnie wpisaną wersję Clone.

Problem ICloneablepolega na tym, że nigdy nie wskazano, czy Clonebyła to płytka czy głęboka kopia, które są bardzo różnymi rzeczami. Fakt, że nie ma, ICloneable<T>może wskazywać na przemyślenia Microsoftu na temat ICloneable

JoshBerke
źródło
9

Matt ma rację, nie używaj go. Stwórz własną Copy()metodę (lub podobną nazwę) i wyjaśnij w publicznym API, czy twoja metoda tworzy głęboką, czy płytką kopię twojego obiektu.

John Rasch
źródło