1

I am a new programmer, learning C# as a hobby. I am writing a library navigator where the user can search books by name, genre, author etc.. I am reaching the end of this project and so far I have tackled all problems and solved them on my own. But I am now stuck and therefore writing on StackOverflow to get help from the experts out there. I will try to explain my issue as clearly as possible.

My program currently features 4 book genres: Horror, Fiction, Fantasy & Mystery.

Since in the future I might add more genres, I do not want to find myself navigating through hundreds of lines of code to edit an if/case statement and add the new genre.

Is there a practical way to centralize all the information that I might edit in the future into one place?

Below are the Lists I declared:

    public static List<string> bookList = new List<string> {"shindler's list", "it", "maltese falcon", "bfg", "hobbit"};
    public static List<string> fiction = new List<string> {"shindler's list"};
    public static List<string> fantasy = new List<string> {"bfg", "hobbit"};
    public static List<string> horror = new List<string> {"it"};
    public static List<string> mystery = new List<string> {"maltese falcon"};

Now, these lists are called from various parts of the code such as this one:

case "1":
                Seperation();
                Console.Clear();

                Console.Write("Enter book name: ");
                var bookTitleUserInput = Console.ReadLine();

                Console.WriteLine("You searched for: " + bookTitleUserInput);

                foreach (string s in bookList)
                {
                    if (s.ToLowerInvariant() == bookTitleUserInput.ToLowerInvariant())
                    {
                        Console.WriteLine("\n");
                        Seperation();
                        OutputBookSummary(bookTitleUserInput.ToLowerInvariant());
                        Seperation();
                        if (fiction.Contains(bookTitleUserInput.ToLowerInvariant()))
                        {
                            Console.WriteLine("Genre: Fiction");
                            Console.WriteLine("\n");
                        }
                        else if (horror.Contains(bookTitleUserInput.ToLowerInvariant()))
                        {
                            Console.WriteLine("Genre: Horror");
                            Console.WriteLine("\n");
                        }
                        else if (mystery.Contains(bookTitleUserInput.ToLowerInvariant()))
                        {
                            Console.WriteLine("Genre: Mystery");
                            Console.WriteLine("\n");
                        }
                        else if (fantasy.Contains(bookTitleUserInput.ToLowerInvariant()))
                        {
                            Console.WriteLine("Genre: Fantasy");
                            Console.WriteLine("\n");
                        }
                        else
                        {
                            Console.WriteLine("");
                        }

                        break;
                    }
                }

And code like:

                case "4":
                Console.Clear();
                Console.WriteLine("Settings Menu");
                Seperation();
                Console.WriteLine("1) Search By Genre");
                Console.WriteLine("2) Search By Author");
                Console.WriteLine("3) Search By Book Name");
                Console.WriteLine("4) Back to Main Menu");
                Seperation();

                Console.Write("Choice: ");
                var settingsMenuSelection = Console.ReadLine();

                switch (settingsMenuSelection)
                {
                    case "1":
                        Console.WriteLine("1) Horror");
                        Console.WriteLine("2) Mystery");
                        Console.WriteLine("3) Fiction");
                        Console.WriteLine("4) Fantasy");
                        var genreMenuSelection = Console.ReadLine();

                        break;

So like this, if I had to edit the code to add more genres, I would have to scroll through my code and edit them individually. Not to mention the mess and confusion this would create..

I have tried putting the if statement block of case 1: in a separate Method but it did not work. I have also tried putting everything in another class and call the blocks case 1: and case 4: from there but that also did not work.

By not working, I mean that Genre: + the genre did not output on the Console.

So, in a nutshell, is there a way to centralize all of the above code so if a new book/genre/author comes along, I won't have to navigate? Because I think that would be bad practice.

Thanks in advance and sorry for the long post!

Patrick
  • 25
  • 3
  • 2
    Well, you have hard coded lists, so you are already "locked in". Usually, you would hold your data in a central data store, for example a database. Then "Genre" would possibly be one table (or collection, but let's stick to relational dbs for the sake of the argument) and the specific genre of a book would be a reference into that table from a column of the "book" table. Your Data Access Layer in the app then will "translate" your business cases into related queries (Create, Read, Update, Delete) into the database. – Fildor Sep 03 '20 at 13:32
  • ^^ So here, if you added one more genre, it would be as easy as inserting another row into the genre table. – Fildor Sep 03 '20 at 13:36
  • As @Fildor said, a database would be ideal, but if you do not want to get that complicated, you could still store them in a JSON or XML file. Then write your data layer that interfaces with that. This also gives you the benefit that if you do later want to migrate to a more traditional database, you just need to alter your data layer. – gmiley Sep 03 '20 at 13:36
  • @gmiley I'd usually agree, _but_ with single-file dbs like SQLite being freely available, I feel like file-based (json/xml) data storage to be inferior. But that's just me. (Everything has its place, though) – Fildor Sep 03 '20 at 13:39
  • 1
    I figured I would put that there as it may be more involved for a new developer to worry about setting that up. Simple file access for small data sets is quite fine for a quick solution that buys time for further research and learning. – gmiley Sep 03 '20 at 13:42
  • Hi guys, thanks so much for contacting me this quickly! I will look into creating a SQL Server Database. Do you think that would explain to me what I need to do to get this done? Or would that be different/more complicated than the SQLite? – Patrick Sep 03 '20 at 13:46
  • @gmiley, I will look into your suggestion as well, thanks! – Patrick Sep 03 '20 at 13:47

1 Answers1

1

Typical solution would be to use object orientation to associate a book with its genre. Something like this

public enum Genre
{
    Horror, Fiction, Fantasy, Mystery
}

public class Book
{
    public string Title { get; }
    public Genre Genre { get; }
    public Book(string title, Genre genre) => (Title, Genre) = (title, genre);
}

and you can filter books by genre or search by title like this:

        var books = new[]
        {
            new Book("bfg", Genre.Fiction),
            new Book("it", Genre.Horror),
        };
        var horrorBooks = books.Where(b => b.Genre == Genre.Horror);
        var foundByname = books.FirstOrDefault(b => b.Title.Contains("MySearchTerm"));

In the future you might want to extend books to have a list of genres instead of a single one. You can also continue adding properties like author, ISBN etc. It is possible to serialize a list of books to a json file for storage, or to store books in a database using something like entity framework. The exact approach would depend on what you would require of the system. I would encourage you you read some articles about databases for more insight into the topic, especially database normalization.

JonasH
  • 28,608
  • 2
  • 10
  • 23