Generics ๐Ÿ“ฆ

One Size Fits All - But Safely!

Beginner Friendly 25 min read Lesson 10 of 11

Hey There! Ready to Learn Generics? ๐Ÿ“ฆ

Generics sounds fancy, but it's actually super simple! It lets you write code that works with any type of data, while keeping everything safe and organized.

Quick Question: Have you ever used a container?
  • ๐Ÿ“ฆ A box can hold books, toys, or clothes
  • ๐Ÿ“ฆ The box is the same - what's inside changes
  • ๐Ÿ“ฆ That's exactly what Generics do!
๐ŸŽฏ After this lesson, you'll be able to:
  • โœ… Explain generics like a pro (but in simple words)
  • โœ… Create generic classes (reusable containers)
  • โœ… Use generic methods (flexible functions)
  • โœ… Add constraints (rules for what types can be used)
  • โœ… Master generic collections (List, Dictionary)

Part 1: What are Generics? (The Easy Way)

In Simple Words: Generics let you write code that works with any type of data, but still keeps everything type-safe (no mistakes!).
๐Ÿ“ฆ The Box Analogy

Think of a generic class as a box:

  • ๐Ÿ“ฆ The box is the same shape (the class)
  • ๐Ÿ“ฆ You can put books in it (strings)
  • ๐Ÿ“ฆ You can put toys in it (integers)
  • ๐Ÿ“ฆ You can put clothes in it (custom objects)
  • ๐Ÿ“ฆ The box remembers what's inside!
That's Generics: One box, many types!
๐Ÿ’ป Code Time!

Generic Class:

// ๐Ÿ“ฆ A Box that can hold ANY type
public class Box<T>  // T = Type placeholder
{
    private T item;  // Can be any type!
    
    public void Store(T value) => item = value;
    public T Retrieve() => item;
}

Using the Box:

// Box for numbers
Box<int> intBox = new Box<int>();
intBox.Store(42);
int value = intBox.Retrieve();  // Safe! No casting!

// Box for text
Box<string> strBox = new Box<string>();
strBox.Store("Hello!");
๐ŸŽ‰ Same class, different types!
๐Ÿ˜‚ Fun Joke: Why did the generic class break up with the specific type? Because it wanted to see other types! (Okay, I'll stop ๐Ÿ˜…)

Part 2: Generic Classes - The Reusable Container

A generic class uses a placeholder type (like T) that you fill in later.

๐Ÿ“ Generic Class Example
// ๐Ÿ“ฆ A generic storage class
public class Storage<T>
{
    private List<T> items = new List<T>();
    
    public void Add(T item) => items.Add(item);
    public T Get(int index) => items[index];
    public int Count => items.Count;
}
๐ŸŽฏ Using It
// Storage for numbers
Storage<int> numStore = new Storage<int>();
numStore.Add(5);
numStore.Add(10);

// Storage for names
Storage<string> nameStore = new Storage<string>();
nameStore.Add("Alice");
nameStore.Add("Bob");

โœ… One class, many types!

Why Use Generic Classes?
  • โœ… Reusable - Write once, use with any type
  • โœ… Type-Safe - No casting errors
  • โœ… Clean - No messy object code

Part 3: Generic Methods - Flexible Functions

A generic method can work with different types, even if the class isn't generic!

๐Ÿ“ Generic Method
public class Helper
{
    // ๐Ÿ”„ Swaps any two values
    public void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }
    
    // ๐Ÿ“ Returns the bigger of two
    public T Max<T>(T a, T b) where T : IComparable<T>
    {
        return a.CompareTo(b) > 0 ? a : b;
    }
}
๐ŸŽฏ Using It
Helper helper = new Helper();

// Swap integers
int x = 5, y = 10;
helper.Swap(ref x, ref y);
// x=10, y=5

// Swap strings
string a = "Hello", b = "World";
helper.Swap(ref a, ref b);

// Get max
int max = helper.Max(5, 10);  // 10

โœ… Same method, different types!

Remember: The <T> after the method name tells C# "This method uses generics!"

Part 4: Generic Constraints - Setting Rules

What are Constraints? They're rules about what types can be used with your generic!
๐Ÿ“ Constraints Examples
// ๐Ÿšซ T must be a class (reference type)
public class Processor<T> where T : class
{
    public T Process(T item) => item;
}

// โœ… T must have a default constructor
public class Creator<T> where T : new()
{
    public T Create() => new T();
}

// ๐Ÿ“Š T must be comparable
public T Max<T>(T a, T b) where T : IComparable<T>
{
    return a.CompareTo(b) > 0 ? a : b;
}
โœ… Why Constraints?
  • โœ… Safety - Only valid types can be used
  • โœ… Features - Access methods like CompareTo()
  • โœ… Clarity - Other developers know what's allowed
Common Constraints:
  • where T : class - T must be a class
  • where T : struct - T must be a struct
  • where T : new() - T must have a default constructor
  • where T : SomeClass - T must inherit from SomeClass

Part 5: Generic Collections - The Most Common Generics

C# has built-in generic collections that you'll use every day!

๐Ÿ“ List<T> - A Flexible List
List<string> names = new List<string>();
names.Add("Alice");
names.Add("Bob");
string first = names[0];

List Like an array that can grow and shrink

๐Ÿ“ Dictionary<TKey, TValue>
Dictionary<string, int> ages = new Dictionary<string, int>();
ages.Add("Alice", 25);
ages.Add("Bob", 30);
int age = ages["Alice"];  // 25

Dictionary Key-Value pairs (like a real dictionary)

Other Useful Collections
// ๐Ÿšถ Queue - First In, First Out
Queue<string> line = new Queue<string>();
line.Enqueue("Person1");
line.Enqueue("Person2");
string next = line.Dequeue();  // "Person1"

// ๐Ÿ“š Stack - Last In, First Out
Stack<string> stack = new Stack<string>();
stack.Push("First");
stack.Push("Second");
string last = stack.Pop();  // "Second"
โœ… Benefits of Generic Collections
  • โœ… Type-Safe - No casting needed
  • โœ… Fast - No boxing/unboxing
  • โœ… Clean - Easy to read and use
  • โœ… Powerful - Built-in methods (Sort, Find, etc.)
Pro Tip: Always use generic collections instead of non-generic ones like ArrayList!

Part 6: Real-World Example - Online Store ๐Ÿ›’

Let's build an Online Store with generics!

// ๐Ÿ›’ Generic Shopping Cart
public class ShoppingCart<T>  // T = Product type
{
    private List<T> items = new List<T>();
    private static int cartCount = 0;
    
    public ShoppingCart() => cartCount++;
    
    public void Add(T item) => items.Add(item);
    public void Remove(T item) => items.Remove(item);
    public int Count => items.Count;
    public static int TotalCarts => cartCount;
    
    public void Display()
    {
        Console.WriteLine($"๐Ÿ“ฆ Cart has {Count} items:");
        foreach (var item in items)
        {
            Console.WriteLine($"   โ€ข {item}");
        }
    }
}

// ๐ŸŽฎ Product classes
public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public override string ToString() => $"{Name} (${Price})";
}

public class DigitalProduct : Product
{
    public string DownloadLink { get; set; }
    public override string ToString() => 
        $"{Name} (Digital, ${Price})";
}
// Program.cs - Shopping System
class Program
{
    static void Main()
    {
        Console.WriteLine("๐Ÿ›’ ONLINE STORE\n");
        
        // ๐Ÿ“ฆ Create products
        Product laptop = new Product 
        { 
            Name = "Gaming Laptop", 
            Price = 999.99m 
        };
        
        DigitalProduct ebook = new DigitalProduct
        {
            Name = "C# Guide",
            Price = 29.99m,
            DownloadLink = "https://example.com/book"
        };
        
        // ๐Ÿ›’ Generic shopping carts
        ShoppingCart<Product> cart1 = new ShoppingCart<Product>();
        cart1.Add(laptop);
        cart1.Add(ebook);
        
        ShoppingCart<string> wishlist = new ShoppingCart<string>();
        wishlist.Add("New Headphones");
        wishlist.Add("Wireless Charger");
        
        // ๐Ÿ“Š Display
        Console.WriteLine("๐Ÿ“ฆ PRODUCT CART:");
        cart1.Display();
        
        Console.WriteLine("\n๐Ÿ’ญ WISHLIST:");
        wishlist.Display();
        
        Console.WriteLine($"\n๐Ÿ“Š Total Carts: {ShoppingCart<Product>.TotalCarts}");
    }
}
๐ŸŽ‰ What this shows:
  • โœ… Generic Class - ShoppingCart works with any type
  • โœ… Type Safety - Product cart vs String wishlist
  • โœ… Static Members - TotalCarts tracks all carts
  • โœ… Inheritance - DigitalProduct inherits from Product
๐Ÿ˜‚ Shopping Joke: Why did the generic shopping cart break up with the specific product? Because it couldn't handle the type of commitment! (Okay, that was a stretch ๐Ÿ˜…)

Part 7: Let's Practice! ๐ŸŽฎ

What You're Building: A Cache System for storing any type of data!
Like a temporary storage that can hold anything.
๐Ÿ—„๏ธ About This Application

This is a Cache System used in:

  • ๐ŸŒ Web Browsers - Store web pages
  • ๐Ÿ“ฑ Apps - Store user preferences
  • ๐Ÿ’พ Databases - Store query results

You'll create a generic cache that can store any type of data:

  • โœ… Store numbers, text, or objects
  • โœ… Check if data is cached
  • โœ… Remove data when needed
  • โœ… Count how many items are cached
Your Mission:
  1. Generic Class: Cache<T>
    • Private field: Dictionary<string, T> (key = cache key)
    • Method: Add(string key, T value)
    • Method: Get(string key) - returns T
    • Method: Remove(string key) - returns bool
    • Method: Clear() - removes all
    • Property: Count - returns number of items
    • Property: Contains(string key) - returns bool
  2. Program.cs:
    • Create Cache<int>, Cache<string>, Cache<Product>
    • Add data to each
    • Retrieve and display data
    • Show cache statistics
๐Ÿ’ก What You're Learning:
  • โœ… Generic Class - Cache works with ANY type
  • โœ… Type Safety - No casting needed
  • โœ… Dictionary - Store by key
  • โœ… Reusable - One class, many uses
Result: A powerful cache system that stores ANY type of data!

๐ŸŽ‰ What You Learned Today!

Generics
Work with any type
Generic Classes
Reusable containers
Generic Methods
Flexible functions
Constraints
Rules for types
Generic Collections
List, Dictionary
Real Example
Online Store! ๐Ÿ›’
Cache System
Store anything!
Test Your Knowledge - Take Quiz