C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
152: Building a Simple E-Commerce Cart System
At this stage in the course, you've got the syntax down, but the real challenge is organizing logic to handle a real-world workflow. We're going to build a simple e-commerce cart. It sounds trivial, but this is where you have to make decisions about how data relates—specifically, how a "Product" differs from a "Cart Item."
Defining what we're actually selling
First, we need a Product. I like to keep this as a simple record or class that acts as a data transfer object. It shouldn't contain any logic; it just tells us what the item is and what it costs.
public record Product(int Id, string Name, decimal Price);
Now, we can't just put a list of Product objects in our cart because we need to track quantity. If a user buys three of the same headphones, we don't want three identical objects in our list—that's a waste of memory and makes updating the cart a nightmare. Instead, I'll create a CartItem class to wrap the product.
public class CartItem
{
public Product Product { get; set; }
public int Quantity { get; set; }
public decimal TotalPrice => Product.Price * Quantity;
public CartItem(Product product, int quantity)
{
Product = product;
Quantity = quantity;
}
}
Setting up the Cart logic
Now for the main engine: the ShoppingCart class. I'll use a List<CartItem> to hold the items. I'm choosing a List here for simplicity, though in a high-performance system, a Dictionary keyed by Product ID might be faster for lookups.
public class ShoppingCart
{
private readonly List<CartItem> _items = new();
public IReadOnlyCollection<CartItem> Items => _items.AsReadOnly();
public void AddItem(Product product, int quantity)
{
var item = new CartItem(product, quantity);
_items.Add(item);
}
public decimal CalculateTotal()
{
return _items.Sum(item => item.TotalPrice);
}
}
The "Double-Add" bug
I just realized I made a classic mistake in the AddItem method above. If you run this code and add "Wireless Mouse" twice, your cart will have two separate entries for the same mouse. From a user experience perspective, that's confusing. The cart should simply increment the quantity of the existing item.
I need to check if the product already exists in the list before adding a new CartItem. I'll use LINQ's FirstOrDefault to find a match.
public void AddItem(Product product, int quantity)
{
var existingItem = _items.FirstOrDefault(i => i.Product.Id == product.Id);
if (existingItem != null)
{
existingItem.Quantity += quantity;
}
else
{
_items.Add(new CartItem(product, quantity));
}
}
Testing the workflow
To make sure this actually works, I'll wire it up in a small console test. Notice how I'm using decimal for prices—never use double or float for money, or you'll eventually run into rounding errors that will make your accountant scream.
var cart = new ShoppingCart();
var laptop = new Product(1, "Gaming Laptop", 1200.00m);
var mouse = new Product(2, "Wireless Mouse", 25.00m);
cart.AddItem(laptop, 1);
cart.AddItem(mouse, 1);
cart.AddItem(mouse, 1); // This should increment the existing mouse entry
Console.WriteLine($"Items in cart: {cart.Items.Count}"); // Should be 2
Console.WriteLine($"Total: ${cart.CalculateTotal()}"); // Should be 1250.00
By separating the Product from the CartItem and fixing that duplication bug, we've built a system that's predictable and easy to extend. You can now easily add features like "Remove Item" or "Clear Cart" without breaking the core logic.
📋 Practical Task
Implement a Promo Code Discount System
Your task is to extend the ShoppingCart class to support a discount system. Modify the existing code to include the following:
- Add a private field
_discountPercentage(a double or decimal) to theShoppingCartclass. - Create a method
ApplyDiscount(decimal percentage)that sets this value (ensure the percentage is between 0 and 100). - Update the
CalculateTotal()method so that it subtracts the discount percentage from the final sum.
Test your implementation by adding a few items to the cart, applying a 10% discount, and verifying that the total is reduced correctly.
There are no comments for now.