Master C# Programming From Scratch

Clear, interactive, and structured coding lessons designed for absolute beginners.

Generics in C#

Generics allow us to create classes, methods, interfaces, and collections that can work with different data types while providing type safety.

Simple Definition: Generics allow us to write reusable code that can work with different data types without rewriting the same code.

Why Do We Use Generics?

Without generics, we may need to create separate classes or methods for different data types. Generics help us write one reusable implementation.

  • Provides type safety.
  • Reduces duplicate code.
  • Improves code reusability.
  • Provides better compile-time checking.
  • Works efficiently with .NET collections.
  • Makes applications easier to maintain.

Generic Syntax

C#
class ClassName<T>
{
    // Class members
}

Here, T represents a type parameter. It can represent different data types such as int, string, double, or custom classes.

Generic Class

A generic class allows us to create a class that can work with different data types.

C#
using System;
 
class Box<T>
{
    public T Value { get; set; }
}

class Program
{
    static void Main()
    {
        Box<int> numberBox = new Box<int>();

        numberBox.Value = 100;

        Console.WriteLine(numberBox.Value);
    }
}
Output
100

Generic Class with Different Data Types

The same generic class can be used with different data types.

C#
using System;
 
class Box<T>
{
    public T Value { get; set; }
}

class Program
{
    static void Main()
    {
        Box<int> numberBox = new Box<int>();
        numberBox.Value = 100;

        Box<string> textBox = new Box<string>();
        textBox.Value = "CIIT";

        Console.WriteLine(numberBox.Value);
        Console.WriteLine(textBox.Value);
    }
}
Output
100
CIIT

Generic Method

A generic method can work with different data types without creating separate methods for each type.

C#
using System;
 
class Program
{
    static void Display<T>(T value)
    {
        Console.WriteLine(value);
    }

    static void Main()
    {
        Display<int>(100);
        Display<string>("Hello");
    }
}
Output
100
Hello

Generic Method Type Inference

C# can often determine the generic type automatically from the value passed to the method.

C#
using System;
 
static void Display<T>(T value)
{
    Console.WriteLine(value);
}

Display(100);
Display("CIIT");
Display(25.5);
Output
100
CIIT
25.5

Generic List

One of the most common examples of generics in C# is List<T>. The type inside < > specifies what type of data the list can store.

C#
using System;
 
List<int> numbers = new List<int>();

numbers.Add(10);
numbers.Add(20);
numbers.Add(30);

foreach (int number in numbers)
{
    Console.WriteLine(number);
}
Output
10
20
30

Generic List with String

C#
using System;
 
List<string> students = new List<string>();

students.Add("Rahul");
students.Add("Sneha");
students.Add("Amit");

foreach (string student in students)
{
    Console.WriteLine(student);
}
Output
Rahul
Sneha
Amit

Generic Dictionary

Dictionary<TKey, TValue> is another commonly used generic collection. It stores data in key-value pairs.

C#
using System;
 
Dictionary<int, string> students =
    new Dictionary<int, string>();

students.Add(101, "Rahul");
students.Add(102, "Sneha");
students.Add(103, "Amit");

Console.WriteLine(students[102]);
Output
Sneha

Generic Interface

Interfaces can also use generic type parameters. This allows an interface to work with different types.

C#
using System;
 
class Storage<T> where T : class
{
    public T Value { get; set; }
}

class Student
{
    public string Name { get; set; }
}

class Program
{
    static void Main()
    {
        Storage<Student> storage = new Storage<Student>();

        storage.Value = new Student
        {
            Name = "Rahul"
        };

        Console.WriteLine(storage.Value.Name);
    }
}
Output
Student Added: Rahul

Generic Constraints

Generic constraints allow us to restrict the types that can be used with a generic class or method.

For example, the where T : class constraint specifies that T must be a reference type.

C#
using System;
 
class Storage<T> where T : class
{
    public T Value { get; set; }
}

class Student
{
    public string Name { get; set; }
}

class Program
{
    static void Main()
    {
        Storage<Student> storage = new Storage<Student>();

        storage.Value = new Student
        {
            Name = "Rahul"
        };

        Console.WriteLine(storage.Value.Name);
    }
}
Output
Rahul

Type Safety with Generics

Generics provide compile-time type checking. This helps prevent invalid data from being added to a strongly typed collection.

C#
using System;
 
List<int> numbers = new List<int>();

numbers.Add(10);
numbers.Add(20);

// numbers.Add("Hello");  // Compile-time error
Important: A List<int> can store only integer values. Trying to add a string will result in a compile-time error.

Generics vs Non-Generic Collections

Feature Generics Non-Generic
Type Safety Strong type safety Less type safety
Performance Generally better May require casting
Code Reusability High Lower
Common Example List<T> ArrayList

Common Generic Types in .NET

Generic Type Purpose
List<T> Stores a dynamic list of strongly typed elements
Dictionary<TKey,TValue> Stores key-value pairs
HashSet<T> Stores unique elements
Queue<T> Stores elements using FIFO behavior
Stack<T> Stores elements using LIFO behavior

Example 👨‍🏫🌍

Generics are widely used in real-world .NET applications. For example, an application may use a generic repository to work with different database entities.

C#
using System;
 
List<string> courses = new List<string>();

courses.Add("C#");
courses.Add(".NET");
courses.Add("ASP.NET Core");

foreach (string course in courses)
{
    Console.WriteLine(course);
}
Output
C#
.NET
ASP.NET Core
CIIT Practical Point: Generics are used extensively in modern .NET development, especially with collections, repositories, services, APIs and reusable business logic.

Common Mistakes with Generics

  • Use the correct generic type for your data.
  • Do not try to add incompatible data types to strongly typed collections.
  • Understand the difference between TKey and TValue in Dictionary.
  • Use generic constraints when a type needs specific requirements.
  • Prefer generic collections for strongly typed application code.

Interview Questions

1. What are Generics in C#?

Generics allow developers to create reusable and type-safe classes, methods, interfaces and collections.

2. What is the advantage of Generics?

Generics provide type safety, code reusability and better maintainability.

3. What is T in Generics?

T is a type parameter that represents a data type.

4. What is a generic class?

A generic class is a class that can work with different data types using a type parameter.

5. What is a generic method?

A generic method is a method that can work with different data types using a type parameter.

6. What is a generic constraint?

A generic constraint restricts the types that can be used as a generic type parameter.

Generics Summary

  • Generics allow reusable and type-safe code.
  • Generic classes can work with different data types.
  • Generic methods can work with different data types.
  • List<T> is a commonly used generic collection.
  • Dictionary<TKey,TValue> stores key-value pairs.
  • Generic constraints restrict valid type parameters.
  • Generics improve code reusability and maintainability.
  • Generics are widely used in modern .NET applications.

Practice Questions

  1. Create a generic class that stores an integer value.
  2. Create a generic class that stores a string value.
  3. Create a generic method to display different data types.
  4. Create a List<int> and add five numbers.
  5. Create a List<string> and add five student names.
  6. Create a Dictionary<int,string> for student records.
  7. Create a generic class with a class constraint.
  8. Explain the difference between generic and non-generic collections.
  9. Explain the advantages of Generics in C#.
  10. Create a generic repository-style class example.