Based on the C# Fundamentals course by Scott Allen. Annotated for learning.
GradeBook/
├── GradeBook.sln # Solution file (groups both projects)
│
├── src/
│ └── GradeBook/ # Main console application
│ ├── GradeBook.csproj
│ ├── Program.cs # Entry point (top-level statements, C# 9+)
│ ├── Delegates.cs # GradeAddedDelegate definition
│ ├── IBook.cs # IBook interface
│ ├── NamedObject.cs # Base class with Name property
│ ├── Book.cs # Abstract class extending NamedObject
│ ├── InMemoryBook.cs # Concrete implementation (grades stored in List<double>)
│ └── Statistics.cs # Data class for computed grade statistics
│
└── test/
└── GradeBook.Tests/ # xUnit test project
├── GradeBook.Tests.csproj
├── BookTests.cs # Tests for grade calculation logic
└── TypeTests.cs # Tests demonstrating C# type system concepts
# Run the console app (interactive grade entry)
cd src/GradeBook
dotnet run
# Run all tests
cd test/GradeBook.Tests
dotnet test
# Or from solution root
dotnet test GradeBook.sln| Concept | File |
|---|---|
| Delegates & Events | Delegates.cs, IBook.cs, InMemoryBook.cs, Program.cs |
| Interfaces | IBook.cs |
| Abstract classes | Book.cs |
Inheritance & base() chaining |
NamedObject.cs → Book.cs → InMemoryBook.cs |
| Method overloading | InMemoryBook.cs (two AddGrade overloads) |
ref / out parameters |
TypeTests.cs |
| Value types vs reference types | TypeTests.cs |
| String immutability | TypeTests.cs |
| Multicast delegates | TypeTests.cs |
switch with pattern matching |
InMemoryBook.cs |
| try / catch / finally | Program.cs |
List<T> generics |
InMemoryBook.cs |
const |
InMemoryBook.cs |
| Top-level statements | Program.cs |
xUnit [Fact] tests |
BookTests.cs, TypeTests.cs |
nameof() & string interpolation |
InMemoryBook.cs |
NamedObject— reusable base for anything with a nameBook(abstract) — enforces that all book types implementAddGradeandGetStatisticsIBook(interface) — letsProgram.csand tests work with any book type without coupling toInMemoryBookInMemoryBook— the concrete grade store; a futureDiskBookcould be added without changing any calling code