Nasze oprogramowanie ma kilka klas, które należy dynamicznie znaleźć poprzez odbicie. Wszystkie klasy mają konstruktor z określoną sygnaturą, za pośrednictwem której kod odbicia tworzy instancję obiektów.
Jednak gdy ktoś sprawdzi, czy metoda jest przywołana (na przykład za pomocą soczewki Visual Studio Code Lens), referencja za pomocą odbicia nie jest liczona. Ludzie mogą przegapić swoje referencje i usunąć (lub zmienić) najwyraźniej nieużywane metody.
Jak powinniśmy oznaczać / dokumentować metody, które mają być wywoływane poprzez refleksję?
Najlepiej byłoby, gdyby metoda została oznaczona w taki sposób, aby zarówno współpracownicy, jak i Visual Studio / Roslyn i inne zautomatyzowane narzędzia „zobaczyli”, że metoda ma zostać wywołana poprzez odbicie.
Znam dwie opcje, których możemy użyć, ale obie nie są całkiem satysfakcjonujące. Ponieważ Visual Studio nie może znaleźć referencji:
- Użyj niestandardowego atrybutu i oznacz konstruktorem tym atrybutem.
- Problem polega na tym, że właściwości atrybutu nie mogą być odwołaniem do metody, dlatego konstruktor nadal będzie pokazywał, że ma 0 odwołań.
- Koledzy nieznający atrybutu niestandardowego prawdopodobnie go zignorują.
- Zaletą mojego obecnego podejścia jest to, że część refleksyjna może użyć atrybutu do znalezienia konstruktora, który powinien wywołać.
- Użyj komentarzy, aby udokumentować, że metoda / konstruktor ma być wywoływany przez odbicie.
- Zautomatyzowane narzędzia ignorują komentarze (i koledzy też mogą to robić).
- Komentarze do dokumentacji XML można wykorzystać, aby Visual Studio zliczało dodatkowe odwołanie do metody / konstruktora:
NiechMyPlugin
będzie klasą, której konstruktor może wywoływać poprzez odbicie. Załóżmy, że wywołujący kod refleksyjny szuka konstruktorów, które pobierająint
parametr. Poniższa dokumentacja pokazuje, że soczewka kodu pokazuje konstruktor mający 1 referencję:
/// <see cref="MyPlugin.MyPlugin(int)"/> is invoked via reflection
Jakie są lepsze opcje?
Jaka jest najlepsza praktyka oznaczania metody / konstruktora, który ma zostać wywołany przez odbicie?
źródło
Odpowiedzi:
Połączenie sugerowanych rozwiązań:
To powinno wyjaśnić zamierzone użycie kolegom (i mojemu przyszłemu ja).
<see>
lewy ” za pomocą -tag, aby zwiększyć liczbę referencji dla konstruktora / metody.To sprawia, że kod obiektywu i referencje wyszukiwania wskazują, że odwołuje się do konstruktora / metody.
UsedImplicitlyAttribute
[UsedImplicitly]
ma dokładnie zamierzoną semantykę.PM>
Install-Package JetBrains.Annotations
.SupressMessageAttribute
tej wiadomościCA1811: Avoid uncalled private code
.Na przykład:
Rozwiązanie zapewnia zamierzone użycie konstruktora zarówno ludzkim czytelnikom, jak i 3 systemom analizy kodu statycznego najczęściej używanym w C # i Visual Studio.
Minusem jest to, że zarówno komentarz, jak i jedna lub dwie adnotacje mogą wydawać się nieco zbędne.
źródło
MeansImplicitUseAttribute
możliwość tworzenia własnych atrybutów, które działająUsedImplicitly
. Może to zmniejszyć wiele szumów atrybutów w odpowiednich sytuacjach.Nigdy nie miałem tego problemu w projekcie .Net, ale regularnie mam ten sam problem z projektami Java. Moim zwykłym podejściem jest użycie
@SuppressWarnings("unused")
adnotacji z komentarzem wyjaśniającym dlaczego (udokumentowanie przyczyny wyłączenia ostrzeżeń jest częścią mojego standardowego stylu kodu - za każdym razem, gdy kompilator nie może czegoś wymyślić, zakładam, że człowiek może się zmagać też). Ma to tę zaletę, że automatycznie zapewnia, że narzędzia analizy statycznej są świadome, że kod nie powinien zawierać bezpośrednich odniesień, i podaje szczegółowy powód dla czytelników.Odpowiednikiem C # języka Java
@SuppressWarnings
jestSuppressMessageAttribute
. W przypadku metod prywatnych możesz użyć komunikatu CA1811: Unikaj nieprzywołanego prywatnego kodu ; na przykład:źródło
SuppressMessageAttribute
( msdn.microsoft.com/en-us/library/… ). Najbliższym komunikatem jestCA1811: Avoid uncalled private code
( msdn.microsoft.com/en-us/library/ms182264.aspx ); Nie znalazłem jeszcze wiadomości dla kodu publicznego.Alternatywą dla dokumentacji byłoby przeprowadzenie testów jednostkowych upewniających się, że wywołania odbicia działają poprawnie.
W ten sposób, jeśli ktoś zmieni lub usunie metody, proces kompilacji / testowania powinien ostrzec cię, że coś zepsułeś.
źródło
Cóż, nie widząc twojego kodu, brzmi to tak, jakby to było dobre miejsce do wprowadzenia dziedziczenia. Może wirtualna lub abstrakcyjna metoda, którą może wywołać konstruktor tych klas? Jeśli jesteś metodą, którą próbujesz oznaczyć, jest tylko konstruktorem, to naprawdę próbujesz oznaczyć klasę, a nie metodę, tak? Coś, co robiłem w przeszłości, aby zaznaczyć klasy, to zrobić pusty interfejs. Następnie narzędzia do inspekcji kodu i refaktoryzacji mogą szukać klas implementujących interfejs.
źródło