Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources

Introduction to Generics in C#

What are Generics?

Generics allow you to define a class, method, delegate, or interface with a placeholder for the type of data it stores or uses. This enables type-safe data structures without committing to actual data types until the class or method is instantiated or called.

Why Use Generics?

Generics provide several benefits:

  • Type Safety: Generics ensure that you can only use the specified data type, reducing runtime errors.
  • Performance: Generics can reduce the need for boxing/unboxing and type casting, which can improve performance.
  • Code Reusability: Generic code can be reused with different data types, reducing code duplication.

Generic Classes

Here's an example of a generic class in C#:


public class GenericClass<T>
{
    private T data;

    public GenericClass(T value)
    {
        data = value;
    }

    public T GetData()
    {
        return data;
    }
}
                

You can use this class with any data type:


GenericClass<int> intInstance = new GenericClass<int>(10);
Console.WriteLine(intInstance.GetData());  // Output: 10

GenericClass<string> stringInstance = new GenericClass<string>("Hello");
Console.WriteLine(stringInstance.GetData());  // Output: Hello
                

Generic Methods

Generic methods allow you to define a method with a type parameter. Here's an example:


public class GenericMethodClass
{
    public void PrintData<T>(T data)
    {
        Console.WriteLine(data);
    }
}
                

Using the generic method:


GenericMethodClass obj = new GenericMethodClass();
obj.PrintData<int>(123);  // Output: 123
obj.PrintData<string>("Generics are powerful!");  // Output: Generics are powerful!
                

Generic Interfaces

Generic interfaces are similar to generic classes. Here's an example:


public interface IGenericInterface<T>
{
    T GetData();
}

public class GenericClassWithInterface<T> : IGenericInterface<T>
{
    private T data;

    public GenericClassWithInterface(T value)
    {
        data = value;
    }

    public T GetData()
    {
        return data;
    }
}
                

Implementing and using the generic interface:


IGenericInterface<int> intInstance = new GenericClassWithInterface<int>(10);
Console.WriteLine(intInstance.GetData());  // Output: 10

IGenericInterface<string> stringInstance = new GenericClassWithInterface<string>("Hello");
Console.WriteLine(stringInstance.GetData());  // Output: Hello
                

Constraints on Generics

Sometimes, you may want to restrict the types that can be used with generics. You can do this using constraints. Here are some examples of constraints:


// T must be a reference type
public class ReferenceTypeConstraint<T> where T : class
{
    // Implementation
}

// T must be a value type
public class ValueTypeConstraint<T> where T : struct
{
    // Implementation
}

// T must have a parameterless constructor
public class ConstructorConstraint<T> where T : new()
{
    // Implementation
}

// T must inherit from a specific base class or implement a specific interface
public class BaseClassConstraint<T> where T : BaseClass
{
    // Implementation
}
                

Conclusion

Generics are a powerful feature in C# that provide type safety, performance benefits, and code reusability. By understanding and utilizing generics, you can write more robust and maintainable code.