Od pewnego czasu stałem się zagorzałym przeciwnikiem używania metod publicznych. W projektach, w których uczestniczę jak tylko mogę zamieniam public na private i/lub internal i proszę o to samo swoich kolegów. Nie wiem, pewnie jakiś wpływ na to miały książki, które ostatnimi czasy czytałem ale to nie ważne 😀
Wiem, że nie wszystko da się zamknąć w klasie, zrobić z niej “zamknięte pudełko” i na tym zakończyć ale większość oczywiście, że tak.
Na bardzo prostym przykładzie chciałbym wyjaśnić dokładnie o co chodzi.

Przypuśćmy, że mamy 2 klasy. Klasa A i klasa B.

Klasa A implementuje pewne funkcjonalności, tak samo jak klasa B.
Nie trzymamy się tutaj żadego wzorca!
Niech klasa A przetwarza jakieś informacje od użytkownika a klasa B zapisuje te informacje do “czegoś” – plik, baza, nie ważne.
Wychodząc z tego założenia klasa A musi utworzyć sobie obiekt klasy B aby wywołać metodę zapisującą te dane. Najprościej jest stworzyć metodę publiczną w klasie B i ją wywołać prawda?

A co jeżeli ktoś będzie chciał zrobić nam przysłowiowe kuku i w swoim projekcie dołączy referencję naszej dll’ki, exe’ca?

kuku

Ano będzie coś takiego jak na screenie powyżej. Ktoś będzie mógł wywołać naszą metodę InsertData. Ja wiem… zabezpieczamy się na różnych poziomach… logowanie użytkownika, sesje i temu podobne. Ale nie o to mi chodzi. Chodzi mi o to aby ten nieszczęsny public zamienić na private i tu właśnie z pomocą przychodzą nam delegaty.
Nie mam zamiaru rozpisywać się na ich temat bo to nie jest artykuł o nich tylko i wyłącznie. Dla osób, które chcą wiedzieć więcej odsyłam do stron MSDN 🙂

Przytaczając przykład, który opisałem wcześniej postaram się wyjaśnić co można zrobić aby taka sytuacja się nie powtórzyła.

Mając za zadanie napisanie klas(y) i nieumożliwienie osobom postronnym wywołania metod mocno wrażliwych (jak InsertData) pierwsze co powinniśmy zrobić to te właśnie metody zamienić na metody prywatne.
I teraz pewna magia 🙂
Dodajemy delegat

internal jest tu użyty celowo.
Wybaczcie mi, ale na temat modyfikatorów dostępu też nie będę się rozpisywał. Zainteresowanych odsyłam do MSDN.

Następnie w klasie, w której mamy naszą metodę insertującą dodajemy metodę, która zwraca nam wcześniej zadeklarowany delegat

Jak widać metoda zwraca nam tak naprawdę definicję metody InsertData, która wygląda właśnie tak:

W tym momencie możemy w klasie, która tworzy sobie obiekt klasy zawierającej metodę insertujcą dodać odpowiednie linijki:

W ten oto prosty sposób możemy wywołać metodę prywatną dzięki delegatom.
Prawda, że proste? 🙂

Patrząc teraz na przysłowiowe “kuku”, po podłączeniu referencji naszego projektu do innego, stworzeniu zmiennej naszej klasy intellisense pokaże coś takiego:

delegates

Wiem, tak samo jak i Wy, że nie jest to do końca rozwiązanie problemu ponieważ istnieją sposoby na to aby wywołać metody prywatne w inny sposób ale o tym może później.
Tak czy inaczej… jeżeli chcecie chronić swój kod używajcie obfuscator’ów będzie trudniej osobom postronnym zrobić naszej aplikacji “kuku” 😉

Kod do przykładu, do którego dodałem jeszcze inne wariacje wywołania metod – z parametrami, ze zwróceniem wartości znajdziecie na github. Projekt CheckReferenceClassLibrary w solucji jest przykładową “aplikacją”, która posiada referencję do naszego projektu.