C# Tutorial

C# String

C# Array

C# Flow Control

C# Class and Object

C# Inheritance

C# Interface

C# Collection

C# Generic

C# File I/O

C# Delegate and Event

C# Exception

C# Process and Thread

C# ADO.NET Database Operations

C# Generic

In this tutorial, we'll cover the basics of using generics in C#. Generics provide a way to create classes, interfaces, and methods with placeholders for the types of their fields, methods, and parameters. This allows you to create more flexible and reusable code.

  • Introduction to Generics

Imagine you want to create a simple class to store a pair of items. You could create a separate class for each possible type of item, but this would lead to a lot of code duplication. Instead, you can use generics to create a single class that can store any type of item.

  • Generic Class

Here's an example of a generic class called Pair that can store two items of any type:

public class Pair<T1, T2>
{
    public T1 First { get; set; }
    public T2 Second { get; set; }

    public Pair(T1 first, T2 second)
    {
        First = first;
        Second = second;
    }
}

The angle brackets <T1, T2> indicate that this is a generic class with two type parameters, T1 and T2. You can use any valid identifier for the type parameters, but it's common to use single uppercase letters like T, U, V, etc.

  • Using Generic Classes

To create an instance of the Pair class, you need to specify the types for T1 and T2:

var pairOfStringAndInt = new Pair<string, int>("Hello", 42);

You can also create instances of the Pair class with other types:

var pairOfIntAndDouble = new Pair<int, double>(1, 3.14);
var pairOfBoolAndString = new Pair<bool, string>(true, "World");
  • Generic Interfaces

You can also create generic interfaces:

public interface IRepository<T>
{
    void Add(T item);
    bool Remove(T item);
    T Find(Func<T, bool> predicate);
    IEnumerable<T> GetAll();
}
  • Implementing Generic Interfaces

Here's an example of a simple in-memory implementation of the IRepository interface:

public class InMemoryRepository<T> : IRepository<T>
{
    private readonly List<T> _items = new List<T>();

    public void Add(T item) => _items.Add(item);

    public bool Remove(T item) => _items.Remove(item);

    public T Find(Func<T, bool> predicate) => _items.FirstOrDefault(predicate);

    public IEnumerable<T> GetAll() => _items;
}
  • Generic Methods

You can also create generic methods within non-generic classes:

public class Utility
{
    public static T Min<T>(T a, T b) where T : IComparable<T>
    {
        return a.CompareTo(b) < 0 ? a : b;
    }
}

In this example, the Min method accepts two arguments of type T and returns the minimum of the two. The where T : IComparable<T> constraint ensures that T implements the IComparable<T> interface, allowing the CompareTo method to be called.

You can use the Min method like this:

int minValue = Utility.Min(5, 10);
string minString = Utility.Min("apple", "banana");

This tutorial only scratches the surface of what you can do with generics in C#. There are many other features, such as generic constraints, co- and contravariant type parameters, and more. Generics are a powerful feature in C# that can

  1. How to use generics in C#:

    • Description: Generics in C# provide a way to create flexible and reusable code that can work with different types without sacrificing type safety.
    • Code:
      using System;
      
      class Program
      {
          static void Main()
          {
              // Example of using generics
              GenericPrinter<int> intPrinter = new GenericPrinter<int>();
              intPrinter.Print(42);
      
              GenericPrinter<string> stringPrinter = new GenericPrinter<string>();
              stringPrinter.Print("Hello, Generics!");
          }
      }
      
      class GenericPrinter<T>
      {
          public void Print(T value)
          {
              Console.WriteLine(value);
          }
      }
      
  2. C# generic class example:

    • Description: Generic classes allow you to create classes that can work with any data type.
    • Code:
      using System;
      
      class Box<T>
      {
          public T Content { get; set; }
      }
      
      class Program
      {
          static void Main()
          {
              // Example of generic class
              Box<int> intBox = new Box<int> { Content = 42 };
              Console.WriteLine(intBox.Content);
      
              Box<string> stringBox = new Box<string> { Content = "C# Generics" };
              Console.WriteLine(stringBox.Content);
          }
      }
      
  3. C# generic method example:

    • Description: Generic methods enable you to create methods that can work with different types.
    • Code:
      using System;
      
      class Program
      {
          static void Main()
          {
              // Example of generic method
              int resultInt = GenericMethod<int>(10);
              string resultString = GenericMethod<string>("C# Generics");
      
              Console.WriteLine(resultInt);
              Console.WriteLine(resultString);
          }
      
          static T GenericMethod<T>(T input)
          {
              return input;
          }
      }
      
  4. Constraints in C# generics:

    • Description: Constraints allow you to restrict the types that can be used with generics based on certain criteria.
    • Code:
      using System;
      
      interface IWritable
      {
          void Write();
      }
      
      class Document : IWritable
      {
          public void Write()
          {
              Console.WriteLine("Writing document...");
          }
      }
      
      class Printer<T> where T : IWritable
      {
          public void PrintDocument(T document)
          {
              document.Write();
          }
      }
      
      class Program
      {
          static void Main()
          {
              // Example of generic with constraints
              Printer<Document> documentPrinter = new Printer<Document>();
              documentPrinter.PrintDocument(new Document());
          }
      }
      
  5. Generic collections in C#:

    • Description: Generics are commonly used with collections to create type-safe and efficient data structures.
    • Code:
      using System;
      using System.Collections.Generic;
      
      class Program
      {
          static void Main()
          {
              // Example of generic collection
              List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
              foreach (int number in numbers)
              {
                  Console.WriteLine(number);
              }
          }
      }
      
  6. C# generic interfaces:

    • Description: Interfaces can also be generic, providing a template for implementing classes with specific types.
    • Code:
      using System;
      
      interface ILogger<T>
      {
          void Log(T message);
      }
      
      class ConsoleLogger<T> : ILogger<T>
      {
          public void Log(T message)
          {
              Console.WriteLine($"Logging: {message}");
          }
      }
      
      class Program
      {
          static void Main()
          {
              // Example of generic interface
              ILogger<string> stringLogger = new ConsoleLogger<string>();
              stringLogger.Log("C# Generics are powerful!");
          }
      }
      
  7. Using generic delegates in C#:

    • Description: Generic delegates like Action and Func allow you to create flexible and type-safe methods.
    • Code:
      using System;
      
      class Program
      {
          static void Main()
          {
              // Example of generic delegates
              Action<string> stringAction = Console.WriteLine;
              stringAction("Hello, Generics!");
      
              Func<int, int, int> add = (a, b) => a + b;
              Console.WriteLine(add(2, 3));
          }
      }
      
  8. C# generic class with multiple type parameters:

    • Description: Generic classes can have multiple type parameters to handle scenarios requiring more than one data type.
    • Code:
      using System;
      
      class Pair<TFirst, TSecond>
      {
          public TFirst First { get; set; }
          public TSecond Second { get; set; }
      }
      
      class Program
      {
          static void Main()
          {
              // Example of generic class with multiple type parameters
              Pair<int, string> data = new Pair<int, string> { First = 42, Second = "C#" };
              Console.WriteLine($"First: {data.First}, Second: {data.Second}");
          }
      }