C# OOP: Generics
Tags: csharp, oop, dotnet, beginners
Published: 2019-05-17 16:32:13

---
title: "C# OOP: Generics"
published: true
description: "Object-oriented programming can be a complex paradigm to learn for a beginner. I will try to explain how some of it works. In this article, we'll cover creating generic methods and classes."
tags: csharp, oop, dotnet, beginners
series: C# OOP
cover_image: https://thepracticaldev.s3.amazonaws.com/i/8mfugn7sct7wfpcduxv0.jpg
canonical_url: https://romig.dev/blog/c-oop-primer-generics
---

Jump to:

- [What is a Generic?](#what-is-a-generic)
  - [Defining a Generic](#defining-a-generic)
- [Generic Method](#generic-method)
- [Generic Class](#generic-class)
- [Constraints](#constraints)
- [Collections](#collections)
- [Benefits](#benefits)

</div>

## What is a Generic?

Generics in OOP allow us to define a specification of a class or method that can be used with any data type. When we design a generic, the data types of the method parameters or class isn't known - not until it is called or instantiated.

### Defining a Generic

A generic class or method can be defined using angle brackets < > and an identifier. The standard identifier used for generics is a capital letter T i.e. `<T>` but any letter can be used - even a word. If it makes sense to use an identifier other than _T_, feel free. It's not a rule, just a guideline that most programmers follow.

```csharp
public static void Method<T>(T param1) { }
```

We can also use multiple generic types if needed, typically the second one is denoted as `<U>`.

```csharp
public static void Method<T, U>(T param1, U param2) { }
```

---

## Generic Method

See the below example of an [overloaded method](/aromig/c-oop-primer-method-overloading-1d0f) that swaps two integers or strings values via reference.

```csharp
using System;

public class Maths {

  public static void Swap(ref int a, ref int b) {
    int temp = a;
    a = b;
    b = temp;
  }

  public static void Swap(ref string a, ref string b) {
    string temp = a;
    a = b;
    b = temp;
  }
}

public class Program {
  public static void Main() {
    int twenty = 20;
    int thirty = 30;
    string forty = "forty";
    string fifty = "fifty";

    Maths.Swap(ref twenty, ref thirty);
    Console.WriteLine("twenty = {0}", twenty);
    Console.WriteLine("thirty = {0}", thirty);

    Maths.Swap(ref forty, ref fifty);
    Console.WriteLine("forty = {0}", forty);
    Console.WriteLine("fifty = {0}", fifty);

  }
}
```

Output:

```
twenty = 30
thirty = 20
forty = fifty
fifty = forty
```

[→ dotnetfiddle](https://dotnetfiddle.net/vWGwm8)


Works like a charm, of course. But what if we added another overload for floats? And another for booleans. And another for class objects. This overloaded method is getting big. Now what if we needed to make a fundamental change to all of the overloads? Wouldn't it be nicer and easier to just have one method to rule them all?

```csharp
using System;

public class Maths {

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

public class Program {
  public static void Main() {
    int twenty = 20;
    int thirty = 30;
    string forty = "forty";
    string fifty = "fifty";

    Maths.Swap<int>(ref twenty, ref thirty);
    Console.WriteLine("twenty = {0}", twenty);
    Console.WriteLine("thirty = {0}", thirty);

    Maths.Swap<string>(ref forty, ref fifty);
    Console.WriteLine("forty = {0}", forty);
    Console.WriteLine("fifty = {0}", fifty);

  }
}
```

Output:

```
twenty = 30
thirty = 20
forty = fifty
fifty = forty
```

[→ dotnetfiddle](https://dotnetfiddle.net/x0gSYy)

Instead of two separate overloaded methods, we can trim it down to just one. The major difference is the `<T>` right after the method name and replacing the data type for the parameters and temp variable with `T` as well.

When we call the method from the Main program, we can specify the data type for _T_. In the first part, we're passing integers so the method is called as `Swap<int>(...)` instead of just `Swap(...)`. In the second part, we do the same thing but since we're passing strings, the method is called as `Swap<string>(...)`.

Although, we can actually omit specifying the _<T>_ type when calling the generic method because the compiler will infer the data type from the arguments being passed.

```csharp
// This works too!
Maths.Swap(ref twenty, ref thirty);
Maths.Swap(ref forty, ref fifty);
```

---

## Generic Class

Classes can be generic along the same lines of thinking. A common use for a generic class is for defining collectios of items, where adding & removing are performed in the same way regardless of data type.

One common generic class is a collection called a stack, where items are **pushed** (added to the top of the stack) and **popped** (removed from the top of the stack). This is referred to as LIFO (Last In, First Out) since the item that is removed on a _pop_ operation is teh last one that was recently added.

![LIFO Example, credit Wikipedia](https://thepracticaldev.s3.amazonaws.com/i/7smeoqdm9u4ok4ncolwx.png)
<center><small>_LIFO Example, credit Wikipedia_</small></center>

While the below example is not the Stack<> class exactly (as defined in the .Net Framework), it should show what we're talking about in regards to a use of a generic class.

```csharp
using System;

public class Stack<T> {
  readonly int max_size;
  int index = 0;
  public int size { get; set; }
  T[] items = null;

  public Stack() : this(100) { } // default max_size of 100

  public Stack(int size) {
    max_size = size;
    items = new T[max_size];
  }

  // Push - Adds item to the top of the stack
  public void Push(T item) {
    if (size >= max_size)
      throw new StackOverflowException();

    items[index++] = item; // adds item in next spot
    size++; // increments actual size
  }

  // Pop - returns item from top and then removes it from the stack
  public T Pop() {
    if (size <= 0)
      throw new InvalidOperationException("Stack is empty, cannot Pop");

    return items[--index]; // decrements by 1 and returns value at index
  }

  // Peek - returns the last item in the listt
  public T Peek() {
    return items[index - 1];
  }

  // Get - returns the value of the specified index
  public T Get(int idx) {
    return items[idx];
  }
}

public class Program
{
  public static void Main() {
    Stack<string> StarWars = new Stack<string>();
    StarWars.Push("The Phantom Menace");
    StarWars.Push("Attack of the Clones");
    StarWars.Push("Revenge of the Sith");
    StarWars.Push("Rogue One");
    StarWars.Push("Solo");
    StarWars.Push("A New Hope");
    StarWars.Push("The Empire Strikes Back");
    StarWars.Push("Return of the Jedi");
    StarWars.Push("The Force Awakens");
    StarWars.Push("The Last Jedi");
    StarWars.Push("The Rise of Skywalker");

    Console.WriteLine("Size of Stack: {0}", StarWars.size);
    Console.WriteLine(StarWars.Peek()); // The Rise of Skywalker
    Console.WriteLine(StarWars.Pop());  // The Rise of Skywalker
    Console.WriteLine(StarWars.Pop());  // The Last Jedi
    Console.WriteLine(StarWars.Peek()); // The Force Awakens
    Console.WriteLine(StarWars.Get(5)); // A New Hope
    Console.WriteLine("Size of Stack: {0}", StarWars.size);
  }
}
```

Output:

```
Size of Stack: 11
The Rise of Skywalker
The Rise of Skywalker
The Last Jedi
The Force Awakens
A New Hope
Size of Stack: 9
```

[→ dotnetfiddle](https://dotnetfiddle.net/cVqGfB)

Remember the [Coords struct](/aromig/c-oop-data-types-structs-and-classes-453p#structs)?

```csharp
struct Coords {
  public int x;
  public int y;

  // constructor
  public Coords(int p1, int p2) {
    x = p1;
    y = p2;
  }
}
```

Use a Generic struct (yes, structs too!) instead and it's no longer limited to integers.

```csharp
using System;

struct Coords<T> {
  public T X;
  public T Y;
}

public class Program
{
  public static void Main()
  {
    Coords<int> intCoords;
    intCoords.X = 1;
    intCoords.Y = 2;
    Console.WriteLine("intCoords = {0}, {1}", intCoords.X, intCoords.Y);

    Coords<float> floatCoords;
    floatCoords.X = 1.23f;
    floatCoords.Y = 4.56f;
    Console.WriteLine("floatCoords = {0}, {1}", floatCoords.X, floatCoords.Y);

    Coords<string> stringCoords;
    stringCoords.X = "Over there";
    stringCoords.Y = "A bit closer";
    Console.WriteLine("stringCoords = {0}, {1}", stringCoords.X, stringCoords.Y);
  }
}
```

Output:

```
intCoords = 1, 2
floatCoords = 1.23, 4.56
stringCoords = Over there, A bit closer
```

[→ dotnetfiddle](https://dotnetfiddle.net/J5Pzof)

---

## Constraints

We can also place a restriction on a generic to only accept a certain type, such as a struct, class or specific class/interface.

A constraint is implemented on a generic by using the _where_ keyword followed by the generic type variable (e.g. T), a colon, and the constraint type.

There are 6 types of constraints:

|                        |     |                                                                    |
| :--------------------- | :-: | ------------------------------------------------------------------ |
| where T : struct       |  →  | Type argument must be a value type                                 |
| where T : class        |  →  | Type argument must be a reference type                             |
| where T : new()        |  →  | Type argument must have a public parameterless constructor         |
| where T : <base class> |  →  | Type argument must inherit from <base class> class                 |
| where T : <interface>  |  →  | Type argument must implement from <interface> interface            |
| where T : U            |  →  | There are two type arguments T and U. T must be inheritted from U. |

Maybe the above example with the Coords struct doesn't make sense for its X & Y values to be strings. Let's add a constraint to it.

```csharp
struct Coords<T> where T : struct {
  public T X;
  public T Y;
}
```

Neat! But why are we constraining with a struct? The table above shows that using a struct constraint will restrict the type argument to value types. Since strings are reference types, this should allow this struct to not accept a string. It will; however, accept a single character though. Unfortunately a generic cannot be constrained to individual data types but this is close enough to demonstrate a constraint.

```csharp
using System;

struct Coords<T> where T : struct {
  public T X;
  public T Y;
}

public class Program
{
  public static void Main()
  {
    Coords<int> intCoords;
    intCoords.X = 1;
    intCoords.Y = 2;
    Console.WriteLine("intCoords = {0}, {1}", intCoords.X, intCoords.Y);

    Coords<float> floatCoords;
    floatCoords.X = 1.23f;
    floatCoords.Y = 4.56f;
    Console.WriteLine("floatCoords = {0}, {1}", floatCoords.X, floatCoords.Y);

    Coords<string> stringCoords;
    stringCoords.X = "Over there";
    stringCoords.Y = "A bit closer";
    Console.WriteLine("stringCoords = {0}, {1}", stringCoords.X, stringCoords.Y);
  }
}
```

[→ dotnetfiddle](https://dotnetfiddle.net/397uBQ)

This would result in an error on the line instantiating _stringCoords_.

```
Compilation error (line 22, col 12): The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Coords<T>'
```

## Collections

As mentioned above, there are collections of generic classes like Stack<>. Another common one is List<>.

| List<>      |     | Function                                |
| :---------- | :-: | :-------------------------------------- |
| .Add()      |  →  | Adds an item at the end of the list     |
| .Clear()    |  →  | Removes all items from the list         |
| .Contains() |  →  | Checks for an item; returns a boolean   |
| .Count      |  →  | Returns the number of items in the list |
| .Insert()   |  →  | Adds an item at a specified index       |

Below is a small example of using the List<> collection.

```csharp
using System;
using System.Collections.Generic;

public class Program
{
  public static void Main()
  {
  List<string> colors = new List<string>();
  colors.Add("Red");
  colors.Add("Green");
  colors.Add("Blue");
  colors.Remove("Green");

  Console.WriteLine("# of Colors: {0}", colors.Count);
  foreach (var color in colors) {
    Console.WriteLine(color);
  }
  }
}
```

Output:

```
# of Colors: 2
Red
Blue
```

[→ dotnetfiddle](https://dotnetfiddle.net/bBK0Rr)

.Net has other several built-in collection classes in the [_System.Collections.Generic_ namespace](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic?view=netframework-4.8), such as Queues, LinkedLists, Dictionaries, etc. The types of collections available in this namespace is fairly diverse so if one of those will provide the functionality of your needs, use them! However if it will make sense to create your own generic collection, go right ahead.

---

## Benefits

- **Reusability:** A single generic type definition can be used for multiple purposes with the same code without any alterations. It's much easier to maintain one version of the method/class than multiple overloads.
- **Type Safety:** Generic data types provide better type safety, especially when used with collections since we need to specify the type of objects that are passed to them. Type checking is done at complile time instead of run-time, allowing bugs to be caught before release.
- **Performance:** Methods & classes utilizing generics provide better performance since they reduce the need for boxing/unboxing (conversion from value type to object and vice versa), and typecasting of the objects used. The actual code for data typed versions of a generic is done on demand instead of multiple typed versions that may not be used.

---

## Awesome stuff!

Generics are a powerful feature of C# that allows us to create more versatile data structures and methods. Using generics can provide great abstraction and extensibility, allowing for code reuse, type-safety, and performance gains. Finding where to use them can take some practice and forethought as it may not be readily apparent. No problem though! Keep the concepts in mind for refactoring opportuntities at the least.