Laboratorium 9: Assembly, Refleksja #
Kod startowy #
- SharpArgs/
- SharpArgs/
- SharpArgs.Console/
- SharpArgs.Tests/
- SharpArgs.sln
- output.txt
- task.en.md
- task.pl.md
Wprowadzenie #
Twoim zadaniem jest zaimplementowanie biblioteki SharpArgs - biblioteki do parsowania argumentów z wiersza poleceń z wykorzystaniem atrybutów oraz refleksji.
Sposób użytkowania biblioteki jest następujący:
- Użytkownik tworzy klasę dziedziczącą po abstrakcyjnej klasie
SharpOptions. - Oznacza wybrane właściwości pochodzącymi z biblioteki atrybutami:
FlagorazOption(patrz Etap 1). - Klasa
SharpParser(patrz Etap 4) jest odpowiedzialna za przetworzenie tablicy argumentówstring[] argsoraz zwrócenie instancji modelu wraz z uzupełnionymi właściwościami.
Punktacja #
- Etap 1:
1pkt za każdy atrybut. - Etap 2:
2pkt za każdą zaimplementowaną metodę. - Etap 3:
2.5pkt za implementację skanowaniaassembly,0.5pkt za prawidłowe wywołanie w metodzieMain. - Etap 4:
3pkt za prawidłowe parsowanie, przypisywanie wartości do modelu i tworzenie błędów.
Wskazówki #
- Microsoft Learn: Attributes
- Microsoft Learn: Retrieving Information Stored in Attributes
- Microsoft Learn: Retrieving Attributes from Class Members
- Microsoft Learn: Assembly Class
- Microsoft Learn: AggregateException Class
Etap 1 (bez testów jednostkowych, wystarczy pokazać prowadzącemu) #
Zaprojektuj następujące atrybuty:
[Flag]dla wartości logicznych (flag, np.--verbose). Posiada parametry pozycyjne:string Id,char Shortoraz opcjonalne:string? Long,string? Help.[Option]dla argumentów nazwanych. Posiada parametry pozycyjne:string Id,char Shortoraz opcjonalne:string? Long,string? Default,bool Required,string? Help.
Opis właściwości #
Id– unikalny w ramach klasy identyfikator atrybutu.Short– krótka forma flagi (jednoznakowa, np.vodpowiada-v).Long– długa forma flagi (np.verboseodpowiada--verbose).Help– tekst pomocy/opisu argumentu.Default– wartość domyślna, używana jeśli argument nie został podany.Required– wymagalność argumentu, domyślnietrue.
Etap 2 (testy jednostkowe, plik SharpOptionsTests.cs)
#
Zaimplementuj następujące metody w dostarczonej abstrakcyjnej klasie bazowej SharpOptions (znajduje się w pliku SharpOptions.cs). Jeżeli w opisie metody mowa o zgłaszaniu wyjątków, to są to już zaimplementowane wyjątki, które można znaleźć w folderze Exceptions/. Metody walidują poprawność użycia atrybutów z pierwszego etapu dla typu dziedziczącego po SharpOptions:
ValidateFlags:- Metoda powinna sprawdzać, czy każda właściwość oznaczona atrybutem
[Flag]ma typbooloraz czy krótkie formy flag nie zawierają duplikatów. - W przeciwnym przypadku zgłasza wyjątki
InvalidTypeExceptionorazDuplicateValuesException<string>.
- Metoda powinna sprawdzać, czy każda właściwość oznaczona atrybutem
ValidateOptions:- Metoda powinna sprawdzać, czy typ każdej właściwości oznaczonej atrybutem
[Option]implementuje interfejsIParsable<>z przestrzeni nazwSystemlub jest równy typowistring. - W przeciwnym przypadku zgłasza wyjątek
InvalidTypeException.
- Metoda powinna sprawdzać, czy typ każdej właściwości oznaczonej atrybutem
W celu znajdowania duplikatów w generycznej kolekcji IEnumerable<T> skorzystaj z gotowej metody FindDuplicates<T> w pliku EnumerableExtensions.cs.
Etap 3 (testowanie poprzez wywołanie w pliku Program.cs)
#
Celem tego etapu jest umożliwienie automatycznego wykrywania wszystkich klas w danym assembly, które dziedziczą po SharpOptions, oraz walidacji ich konfiguracji. Wszystkie błędy walidacji mają być zbierane w jednym wyjątku AggregateException.
Walidacja powinna być realizowana za pomocą statycznej klasy SharpOptionsAssemblyValidator (plik SharpOptionsAssemblyValidator.cs):
- Walidator powinien przeszukać
assemblyi znaleźć wszystkie typy dziedziczące poSharpOptions. - Dla każdego typu powinna zostać wywołana metoda
ValidateModel()w celu sprawdzenia konfiguracji flag i opcji. - Wszystkie wyjątki walidacyjne (pochodne
SharpArgsException) należy zebrać i zgłosić w postaci pojedynczegoAggregateException.
Użyj zaimplementowanego walidatora dla bieżącego assembly w metodzie Main w klasie Program (plik Program.cs).
Etap 4 (testy jednostkowe, plik SharpParserTests.cs)
#
Celem tego etapu jest rozpoznanie w modelu wszystkich właściwości oznaczonych atrybutem [Flag], a następnie sparsowanie oryginalnej tablicy argumentów string[] args zgodnie z tym modelem.
- Logika związana z parsowaniem powinna się znaleźć w klasie
SharpParser(plikSharpParser.cs). - Krótkie formy flag rozpoczynają się od pojedynczego myślnika (
-), a długie formy od dwóch (--). - Metoda powinna tworzyć instancję modelu (przy pomocy
Activator.CreateInstance) i ustawiać jego flagi zgodnie z podaną tablicą argumentów. - Metoda powinna zwracać obiekt klasy
ParseResult<T>(klasa jest już gotowa w plikuParseResult.cs), zawierający uzupełniony model lub kolekcję błędów parsowania. - Pojawienie się w tablicy
string[] argsnieznanej flagi (lub elementu niezaczynającego się od-lub--) powoduje dodanie do kolekcji błędów wpisu:"Unknown option: {arg}.".
Przykładowe rozwiązanie #
- SharpArgs/
- SharpArgs/
- SharpArgs.Console/
- SharpArgs.Tests/
- SharpArgs.sln