Menu
Coddy logo textTech

Generics (Classes & Methods)

Part of the Object Oriented Programming section of Coddy's C# journey — lesson 42 of 70.

Generics allow you to write classes and methods that work with any data type while maintaining type safety. Instead of writing separate classes for IntList, StringList, and DoubleList, you write one generic class that handles them all.

A generic class uses a type parameter, typically named T, enclosed in angle brackets:

public class Box<T>
{
    private T content;
    
    public void Store(T item) => content = item;
    public T Retrieve() => content;
}

// Usage with different types
Box<int> intBox = new Box<int>();
intBox.Store(42);

Box<string> stringBox = new Box<string>();
stringBox.Store("Hello");

When you create Box<int>, the compiler replaces every T with int. This provides compile-time type checking - you can't accidentally store a string in an int box.

Generic methods work similarly, allowing a single method to operate on different types:

public static void Swap<T>(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = temp;
}

int x = 1, y = 2;
Swap(ref x, ref y);  // x=2, y=1

The compiler infers the type from the arguments, so you don't need to write Swap<int> explicitly. Generics are the foundation of collections like List<T> and Dictionary<TKey, TValue>, enabling reusable, type-safe code.

challenge icon

Challenge

Easy

Let's build a generic Storage<T> system that can hold and manage items of any type. You'll create a reusable container class that demonstrates the power of generics - write once, use with integers, strings, or any other type!

You'll organize your code across two files:

  • Storage.cs: Create a generic Storage<T> class in the DataStorage namespace. Your storage container should:
    • Have a private array of type T to hold items and a Count property tracking how many items are stored
    • Accept a capacity in its constructor to initialize the internal array
    • Have an Add(T item) method that adds an item if there's room
    • Have a Get(int index) method that returns the item at the specified index
    • Have a GetAll() method that returns all stored items joined by ", "
  • Program.cs: In your main file, demonstrate your generic class working with two different types. Create a Storage<int> and a Storage<string>, add items to each, and show that the same class works seamlessly with both types.

You will receive four inputs:

  • First integer to store
  • Second integer to store
  • First string to store
  • Second string to store

Create an integer storage with capacity 5 and a string storage with capacity 5. Add the two integers to the integer storage and the two strings to the string storage.

Print the output in this format:

Int storage: {GetAll()}
Int count: {Count}
First int: {Get(0)}
String storage: {GetAll()}
String count: {Count}
First string: {Get(0)}

For example, if the inputs are 42, 100, Hello, and World, the output should be:

Int storage: 42, 100
Int count: 2
First int: 42
String storage: Hello, World
String count: 2
First string: Hello

Notice how you write the Storage<T> class once, but it works perfectly with both int and string - that's the magic of generics! The compiler ensures type safety, so you can't accidentally add a string to your integer storage.

Cheat sheet

Generics allow you to write classes and methods that work with any data type while maintaining type safety.

A generic class uses a type parameter (typically T) enclosed in angle brackets:

public class Box<T>
{
    private T content;
    
    public void Store(T item) => content = item;
    public T Retrieve() => content;
}

When creating an instance, specify the type to replace T:

Box<int> intBox = new Box<int>();
intBox.Store(42);

Box<string> stringBox = new Box<string>();
stringBox.Store("Hello");

Generic methods allow a single method to operate on different types:

public static void Swap<T>(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = temp;
}

int x = 1, y = 2;
Swap(ref x, ref y);  // Compiler infers type from arguments

Generics provide compile-time type checking and are the foundation of collections like List<T> and Dictionary<TKey, TValue>.

Try it yourself

using System;
using DataStorage;

class Program
{
    public static void Main(string[] args)
    {
        // Read inputs
        int num1 = Convert.ToInt32(Console.ReadLine());
        int num2 = Convert.ToInt32(Console.ReadLine());
        string str1 = Console.ReadLine();
        string str2 = Console.ReadLine();

        // TODO: Create a Storage<int> with capacity 5
        
        // TODO: Add the two integers to the integer storage
        
        // TODO: Create a Storage<string> with capacity 5
        
        // TODO: Add the two strings to the string storage
        
        // TODO: Print the output in the required format
        // Int storage: {GetAll()}
        // Int count: {Count}
        // First int: {Get(0)}
        // String storage: {GetAll()}
        // String count: {Count}
        // First string: {Get(0)}
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming