Book and User Models
Part of the Object Oriented Programming section of Coddy's C# journey — lesson 63 of 70.
Challenge
EasyLet's expand your Library System by building out the Book and User models with richer functionality. You'll add status tracking for books, borrowing capabilities for users, and proper encapsulation to keep your data safe.
You'll continue working with your four-file structure:
Book.cs: Enhance your Book class with a unique identifier and status tracking. Each book should have anId(string),Title(string),Author(string), andIsAvailable(bool, defaulting to true). Add methodsBorrow()andReturn()that change the availability status and return a message indicating success or failure. If someone tries to borrow an unavailable book, return"{Title} is not available". If they try to return an already available book, return"{Title} was not borrowed". Successful operations should return"{Title} has been borrowed"or"{Title} has been returned".User.cs: Expand your User class to track borrowed books. IncludeName(string),MemberId(int), and a private list to store borrowed book IDs. Add aBorrowedCountread-only property that returns how many books the user currently has. Include methodsAddBorrowedBook(string bookId)andRemoveBorrowedBook(string bookId)to manage the user's borrowed books. Also add aHasBook(string bookId)method that returns true if the user has borrowed that specific book.Library.cs: Your Library class should maintain collections of books and users. Include methodsAddBook(Book book)andRegisterUser(User user)to populate the library. Add aGetBookById(string id)method that returns the book with that ID (or null if not found), andGetUserById(int memberId)that works similarly for users.Program.cs: Bring everything together by processing library operations based on input.
You will receive the following inputs:
- Library name
- Number of books to add
- For each book:
id|title|author - Number of users to register
- For each user:
name|memberId - Number of operations to perform
- For each operation:
action|bookId|memberIdwhere action is eitherborroworreturn
For each operation, print the result of the borrow or return action. After all operations, print a summary for each user showing their name and how many books they currently have borrowed in the format {Name}: {BorrowedCount} book(s).
For example, if the inputs are:
Downtown Library
2
B001|Clean Code|Robert Martin
B002|Design Patterns|Gang of Four
2
Alice|101
Bob|102
4
borrow|B001|101
borrow|B002|101
borrow|B001|102
return|B001|101The output should be:
Clean Code has been borrowed
Design Patterns has been borrowed
Clean Code is not available
Clean Code has been returned
Alice: 1 book(s)
Bob: 0 book(s)Notice how Alice successfully borrows two books, but when Bob tries to borrow Clean Code (which Alice already has), the operation fails. After Alice returns Clean Code, her count drops to 1. This demonstrates how your models work together to enforce library rules!
Try it yourself
using System;
using System.Collections.Generic;
namespace LibrarySystem
{
class Program
{
public static void Main(string[] args)
{
// Read library name
string libraryName = Console.ReadLine();
// Create a Library instance with the library name
Library library = new Library(libraryName);
// Read number of books
int numBooks = Convert.ToInt32(Console.ReadLine());
// Read and add books
for (int i = 0; i < numBooks; i++)
{
string bookInput = Console.ReadLine();
string[] bookParts = bookInput.Split('|');
string bookId = bookParts[0];
string bookTitle = bookParts[1];
string bookAuthor = bookParts[2];
Book book = new Book(bookId, bookTitle, bookAuthor);
library.AddBook(book);
}
// Read number of users
int numUsers = Convert.ToInt32(Console.ReadLine());
// Read and register users
List<User> usersList = new List<User>();
for (int i = 0; i < numUsers; i++)
{
string userInput = Console.ReadLine();
string[] userParts = userInput.Split('|');
string userName = userParts[0];
int memberId = Convert.ToInt32(userParts[1]);
User user = new User(userName, memberId);
library.RegisterUser(user);
usersList.Add(user);
}
// Read number of operations
int numOperations = Convert.ToInt32(Console.ReadLine());
// Process operations
for (int i = 0; i < numOperations; i++)
{
string operationInput = Console.ReadLine();
string[] opParts = operationInput.Split('|');
string action = opParts[0];
string bookId = opParts[1];
int memberId = Convert.ToInt32(opParts[2]);
Book book = library.GetBookById(bookId);
User user = library.GetUserById(memberId);
if (action == "borrow")
{
string result = book.Borrow();
Console.WriteLine(result);
if (result.Contains("has been borrowed"))
{
user.AddBorrowedBook(bookId);
}
}
else if (action == "return")
{
string result = book.Return();
Console.WriteLine(result);
if (result.Contains("has been returned"))
{
user.RemoveBorrowedBook(bookId);
}
}
}
// Print summary for each user
foreach (User user in usersList)
{
Console.WriteLine($"{user.Name}: {user.BorrowedCount} book(s)");
}
}
}
}All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesNamespaces & DirectivesIntro to Classes & ObjectsThe 'this' KeywordMethods and ParametersFields vs PropertiesConstructorsObject InitializersRecap - Simple Calculator4Inheritance
Basic Inheritance (:) SyntaxThe 'base' KeywordVirtual & Override KeywordsSealed ClassesThe 'object' Base ClassRecap - Employee Hierarchy7Advanced Features
Operator OverloadingIndexers (this[])ToString() OverrideExtension MethodsRecap - Custom List2Properties & Static Members
Auto-Implemented PropertiesRead/Write-Only PropertiesStatic Fields & MethodsStatic ClassesExpression-Bodied Members5Polymorphism & Interfaces
Compile vs Runtime PolyInterface vs Abstract ClassMultiple InterfacesExplicit InterfacesUpcasting & DowncastingRecap - Shape Calculator3Class Architecture
Instance vs Static Data'readonly' & 'const' KeywordsBacking FieldsRecap - Bank Account Manager6Encapsulation
Access ModifiersProperties for EncapsulationData Hiding ImplementationImmutability PatternsRecap - Student Records12Project: Library System
Project StructureBook and User ModelsBorrowing System LogicLINQ for SearchingConsole UI / Admin InterfaceUnit Testing (NUnit/xUnit)