Prezentuję całkiem fajny projekt do napisania dla wszystkich, którzy uczą się programowania w C#. Będzie to coś w stylu archiwum domowej biblioteczki. W pliku przechowujemy listę książek, którą program wczytuje przy starcie, następnie możemy te książki usuwać z listy, dodawać nowe, wyszukiwać po trzech różnych parametrach, i ostatecznie zapisać zmodyfikowaną listę z powrotem do pliku.
Mamy więc prosty, ale w pełni funkcjonalny program konsolowy. Opcje:
- wczytanie listy książek z pliku przy starcie
- dodanie nowej książki
- usunięcie książki z listy
- wyświetlenie wszystkich książek
- wyszukanie książki po tytule, autorze lub gatunku
- zapisanie zmodyfikowanej listy
Zacznijmy od zdefiniowania naszej książki – tworzymy klasę Book.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class Book { public int NumPages; public string Author, Title, Type, ReleaseDate; public Book(string title, string author, string type, int pages, string releaseDate) { Title = title; Author = author; Type = type; NumPages = pages; ReleaseDate = releaseDate; } public string BookInfo() { string s = $"'{Title}' ({Type}), {Author}, {NumPages} pages, year: {ReleaseDate}."; return s; } } |
Klasa książki ma kilka podstawowych parametrów, które ją opisują (autor, tytuł, liczba stron itp), konstruktor, który te pola inicjalizuje, oraz metodę BookInfo, która po prostu zwraca opis książki w pewnym formacie.
Przejdźmy teraz do początku programu, metody Main() – tu mamy zadeklarowaną zmienną command (będziemy jej używać do obsługi menu) i listę naszych książek (bookList). Następnie z pliku books.txt wczytujemy zawartość, czyli listę książek, na których będziemy mogli operować w programie (format pliku tekstowego poniżej). Opcja ReadAllLines powoduje wczytanie każdego wiersza z pliku do kolejnego elementu tablicy fBooks, dzięki czemu łatwiej potem nimi operować. (Tak po prawdzie, to należałoby sprawdzić czy plik istnieje przed próbą wczytania go… optymistycznie zakładam, że istnieje.) Kolejna rzecz, którą musimy zrobić, to rozbicie wiersza (elementu tablicy) na poszczególne składniki książki, które następnie posłużą nam do utworzenia nowego obiektu typu Book oraz dodania go do listy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
string command = ""; List<Book> bookList = new List<Book>(); string[] fBooks = File.ReadAllLines("books.txt"); if (fBooks.Length > 0) { for (int i = 0; i < fBooks.Length; i++) { string[] book = fBooks[i].Split(';'); // split book elements (title, author etc) if (book.Length == 5) { string title = book[0]; string author = book[1]; string type = book[2]; int numPages = int.Parse(book[3]); string releaseDate = book[4]; bookList.Add(new Book(title, author, type, numPages, releaseDate)); } } } |
1 2 3 4 5 |
Colour of magic;Terry Pratchett;fantasy;289;1985 Amazonka;James Rollins;thriller;547;2009 Carrie;Stephen King;thriller;275;1988 Metro 2033;Dmitry Gluchovsky;thriller;368;2015 Gringo;W. Cejrowski;adventure;357;2012 |
Gdy mamy już załadowane dane, możemy przejść do głównej pętli programu – będzie to pętla do…while, zawierająca całe menu oraz zdarzenia następujące po wybraniu konkretnej opcji.
Do dzieła więc – pierwsze linie kodu wewnątrz pętli to nasze menu (poniżej). Zwracam uwagę na drobny “ficzer” – przy opcji wyświetlania listy książek od razu podaję ile ich mamy na liście.
1 2 3 4 5 6 7 8 9 |
Console.WriteLine("\nMENU:"); Console.WriteLine("1. Add book"); Console.WriteLine("2. Show books ({0})", bookList.Count); Console.WriteLine("3. Save book list"); Console.WriteLine("4. Find a book"); Console.WriteLine("5. Remove book from list"); Console.WriteLine("'exit' for exit"); Console.Write("Option: "); command = Console.ReadLine(); |
Teraz przechodzimy do oprogramowania kolejnych opcji.
Na początek dodawanie nowej książki do listy – nic trudnego, wystarczy pobrać od użytkownika informacje, a następnie na ich podstawie utworzyć na liście nowy obiekt książki.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
if (command == "1") { Console.Write("\nTitle: "); string title = Console.ReadLine(); Console.Write("Author: "); string author = Console.ReadLine(); Console.Write("Type: "); string type = Console.ReadLine(); Console.Write("Release year: "); string release = Console.ReadLine(); Console.Write("Number of pages: "); int pages = int.Parse(Console.ReadLine()); bookList.Add(new Book(title, author, type, pages, release)); Console.WriteLine("Book added."); } |
Opcja numer 2 to zwykłe wyświetlenie elementów listy, korzystające z metody bookInfo() klasy Book.
1 2 3 4 5 6 7 8 |
else if (command == "2") { Console.WriteLine(); foreach (var book in bookList) { Console.WriteLine(book.BookInfo()); } } |
Opcja numer 3 to zapisanie listy do pliku; zanim jednak to zrobimy, musimy “złożyć” dane w odpowiedni format. W tym celu tworzymy nową listę (właściwie to mogłaby być również tablica o ilości elementów bookList.Count), a następnie w pętli przechodzimy przez wszystkie książki, tworząc ciąg danych rozdzielony średnikiem. Opcja WriteAllLines powoduje zapisanie każdego elementu tablicy lub listy w osobnym wierszu (podobnie jak opcja ReadAllLines odczytuje po wierszu do tablicy).
1 2 3 4 5 6 7 8 9 10 11 12 13 |
else if (command == "3") { List<string> s = new List<string>(); foreach (var book in bookList) { string temp = $"{book.Title};{book.Author};{book.Type};{book.NumPages};{book.ReleaseDate}"; s.Add(temp); } File.WriteAllLines("books.txt", s); Console.WriteLine("File saved."); } |
Opcja numer 4 – wyszukiwarka. Najdłuższy kod, ale założenia są dość proste. Prosimy użytkownika o wpisanie szukanego elementu według podanego wzoru, przykładowo jeśli szukamy po tytule to “title Szukany Tytuł”. Następnie dzielimy otrzymany od użytkownika tekst po spacji na dwie części – spodziewamy się w pierwszym członie znaleźć kryterium wyszukiwania (autor, tytuł lub typ). Tworzymy instrukcję switch, która dopasowuje otrzymany tekst z wytyczonymi przez nas kryteriami. Jeśli znajdzie dopasowanie, przegląda wszystkie książki w poszukiwaniu tych pasujących, i dodaje je do specjalnej listy result (nie wiemy ile tych wyników będzie). Jeśli książka zostanie znaleziona, zwiększamy też licznik count, informujący czy wyszukiwanie przyniosło jakieś rezultaty. Jeśli przyniosło, to wyświetlamy listę znalezionych książek, a jeśli nie (count == 0) to odpowiedni komunikat.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
else if (command == "4") { Console.WriteLine("\nTo find a specific book, please type 'author stephen king' or 'title carrie' or 'type thriller' etc: "); string a = Console.ReadLine(); int count = 0; List<Book> result = new List<Book>(); string[] search = a.Split(' ', 2); if (search.Length > 1) { switch (search[0].ToLower()) { case "author": foreach(var book in bookList) { if (book.Author.ToLower() == search[1].ToLower()) { result.Add(book); count++; } } break; case "title": foreach (var book in bookList) { if (book.Title.ToLower() == search[1].ToLower()) { result.Add(book); count++; } } break; case "type": foreach (var book in bookList) { if (book.Type.ToLower() == search[1].ToLower()) { result.Add(book); count++; } } break; default: Console.WriteLine("Bad input."); break; } } if (count == 0) { Console.WriteLine($"Sorry, no books found for '{a}'."); } else { foreach(var r in result) { Console.WriteLine(r.BookInfo()); } } } |
Opcja 5 to usunięcie książki z listy. Prosimy użytkownika o podanie tytułu, odnajdujemy odpowiedni element (lub elementy), a następnie usuwamy z wykorzystaniem metody RemoveAt(), która usuwa element na podstawie indeksu w liście. Liczymy też ile książek zostało usuniętych (count).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
else if (command == "5") { Console.Write("Title of book you want to remove: "); string t = Console.ReadLine(); int count = 0; for (int i = 0; i < bookList.Count; i++) { if (bookList[i].Title.ToLower() == t.ToLower()) { bookList.RemoveAt(i); count++; } } Console.WriteLine($"{count} book(s) removed."); } |
I to w zasadzie tyle. Na końcu mamy jeszcze obsługę komendy “exit” oraz klauzulę else, informującą o niepoprawnych danych wejściowych.
1 2 3 4 5 6 7 8 |
else if (command == "exit") { break; } else { Console.WriteLine("Invalid input. Choose option 1, 2 etc or type 'exit'."); } |
Można by tu jeszcze dołożyć kilka elementów (np możliwość edycji książki), poprawić to i owo (uodpornić program na użytkowników :)), ale nawet w tej postaci jest to całkiem fajna, działająca aplikacja. W sam raz na pierwszy w miarę kompletny projekt, wykorzystujący podstawowe elementy języka C#.