Generics ๐ฆ
One Size Fits All - But Safely!
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.
- ๐ฆ A box can hold books, toys, or clothes
- ๐ฆ The box is the same - what's inside changes
- ๐ฆ That's exactly what Generics do!
- โ 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)
๐ฆ 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!
๐ป 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!");
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!
- โ Reusable - Write once, use with any type
- โ Type-Safe - No casting errors
- โ
Clean - No messy
objectcode
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!
<T> after the method name tells C# "This method uses generics!"
Part 4: Generic Constraints - Setting Rules
๐ 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
where T : class- T must be a classwhere T : struct- T must be a structwhere T : new()- T must have a default constructorwhere 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.)
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}");
}
}
- โ 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
Part 7: Let's Practice! ๐ฎ
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:
-
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
-
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
// ===== CACHE SYSTEM =====
// A generic cache that can store ANY type
public class Cache<T>
{
private Dictionary<string, T> data = new Dictionary<string, T>();
private static int cacheCount = 0;
public Cache() => cacheCount++;
// Add or update
public void Add(string key, T value)
{
data[key] = value;
Console.WriteLine($"โ
Added: {key} โ {value}");
}
// Get value by key
public T Get(string key)
{
if (data.ContainsKey(key))
{
Console.WriteLine($"๐ค Retrieved: {key} โ {data[key]}");
return data[key];
}
Console.WriteLine($"โ Key '{key}' not found");
return default(T);
}
// Remove by key
public bool Remove(string key)
{
if (data.Remove(key))
{
Console.WriteLine($"๐๏ธ Removed: {key}");
return true;
}
Console.WriteLine($"โ Key '{key}' not found");
return false;
}
// Clear all data
public void Clear()
{
data.Clear();
Console.WriteLine("๐งน Cache cleared");
}
// Properties
public int Count => data.Count;
public bool Contains(string key) => data.ContainsKey(key);
public static int TotalCaches => cacheCount;
public void DisplayAll()
{
Console.WriteLine($"๐ Cache has {Count} items:");
foreach (var kvp in data)
{
Console.WriteLine($" โข {kvp.Key}: {kvp.Value}");
}
}
}
// Simple Product class for testing
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public override string ToString() => $"{Name} (${Price})";
}
// Program.cs - Testing the Cache
class Program
{
static void Main()
{
Console.WriteLine("๐๏ธ CACHE SYSTEM\n");
// ๐ฆ Cache for numbers
Cache<int> numCache = new Cache<int>();
numCache.Add("age", 25);
numCache.Add("score", 100);
// ๐ฆ Cache for text
Cache<string> textCache = new Cache<string>();
textCache.Add("name", "Alice");
textCache.Add("city", "New York");
// ๐ฆ Cache for products
Cache<Product> productCache = new Cache<Product>();
productCache.Add("laptop", new Product { Name = "Gaming Laptop", Price = 999.99m });
Console.WriteLine();
// ๐ Retrieve data
int age = numCache.Get("age");
string name = textCache.Get("name");
Product laptop = productCache.Get("laptop");
Console.WriteLine();
// ๐ Display all caches
Console.WriteLine("๐ CACHE STATISTICS:");
Console.WriteLine($"Total Caches: {Cache<int>.TotalCaches}");
Console.WriteLine("\n๐ข Number Cache:");
numCache.DisplayAll();
Console.WriteLine("\n๐ Text Cache:");
textCache.DisplayAll();
Console.WriteLine("\n๐ฆ Product Cache:");
productCache.DisplayAll();
// ๐๏ธ Remove and check
Console.WriteLine("\n๐๏ธ Removing 'score':");
numCache.Remove("score");
Console.WriteLine($"Contains 'score'? {numCache.Contains("score")}");
}
}