Skip to main content

Command Palette

Search for a command to run...

C# Generic

Updated
5 min read
C# Generic

Introduction

Hello all, today I back with another C# topic, and today I will share what i learned about C# Generic. I hope with this article you will know more about C# Generic and use it on your project.

What It Is?

Introduced in C# 2.0, generic provide a placeholder mechanism for defining types in classes, interfaces, or methods that can be replaced with specific types as needed, such as int, float, or string. These placeholders, known as type parameters, allow the same code to work with different data types while maintaining type safety.

Why Implement It?

There are several pros and cons to consider before implement a generic in our project. Here are some of them:

Pros

  • Enhance code reusability.

  • Reducing runtime errors related to type mismatches.

  • Reduce the need to boxing and unboxing by enabling operations on value types directly.

Cons

  • Could potentially increase code size.

  • It may be challenging for new programmers to understand.

  • Could potentially impact performance because the Just-In-Time (JIT) compiler generates specific code for each generic type.

How It Works?

To understand how generic work in the system, let's implement it first. To implement a generic, all you need to do is add <T> after the method or class name, as shown in the code below:

namespace Lncodes.Example.Generic;

public sealed class QuizController<TQuestion, TCorrectAnswer>
{
    private readonly TQuestion _question;
    private readonly TCorrectAnswer _correctAnswer;

    public QuizController(TQuestion question, TCorrectAnswer correctAnswer) =>
       (_question, _correctAnswer) = (question, correctAnswer);
}

In the code above, I created a generic QuizController class with generic variables named _question and _correctAnswer. By using generic, I can customize the _question and _correctAnswer variable types as needed. After implementing generic, here's what happens in the system:

  1. When a generic type is defined using a specific reference type, the compiler sets up the generic class with a flexible type parameter. For example, if a QuizController<T> class is defined with the int type, the compiler prepares the class for this specific type in Microsoft Intermediate Language (MSIL).

  2. When a specific generic class is prepared and the program is running, the Just-In-Time (JIT) compiler generates a specialized version of the generic type. For example, if QuizController<T> is instantiated with the int type, the JIT compiler creates a QuizController<int> class at runtime.

  3. When a generic type is initialized with previously used type parameters, the system reuses the specialized version of the generic type that was already created by the JIT compiler. This reuse reduces the amount of generated code by minimizing the number of specialized classes created by the JIT compiler.

  4. When assigning a type to a generic, the system by default allows any type to be assigned. However, adding a constraint limits which types can be used. To add a constraint, use the where keyword after the class name. For example, in QuizController where TAnswer : List, the TAnswer type must be a List or any class that inherits from List.

Console Application

In my console application, I use generic for my QuizController class, allowing me to customize the types of question, answer, and choices based on my needs.

Below is a list of the classes I used to create this console application, along with a brief explanation of each class:

ClassDescription
QuizControllerThis class is used to manage quiz-related operations such as adding and deleting items.
ProgramThis class is used to display the quiz operation on the console.

In the video above, the console application demonstrates three quiz variations, each using different data types for the answers and choices. All of these variations are managed by a single generic class called QuizController.

By using generic, handling different data types within a single class is greatly simplified. Instead of creating multiple versions of a class to accommodate different data types, a single generic class can be used to handle any type. This flexibility ensures that the code remains cleaner, more consistent, and easier to maintain over time, while also reducing the complexity of managing similar classes.

The source code for this console application can be viewed and downloaded at Project Repository – Github.

Additional Information

I have discovered some additional information about C# Generic. If you have any additional information about C# Generic that you'd like to share, please feel free to leave a comment.

Naming Guidelines

When implementing generics, following specific naming guidelines can help ensure code readability and consistency. Here are some naming conventions recommended by Microsoft:

  • Do use a 'T' prefix with descriptive names for generic type parameters, e.g. QuizController<TQuestion>.

  • Consider using the single character 'T' for generic type parameters when there is only one type parameter, e.g. QuizController<T>.

  • Consider using names that indicate the constraints of generic type parameters when the generic has constraints, e.g. QuizController<TChoicesCollection> where TChoicesCollection : ICollection.

Further Discoveries

Here are some further discoveries I have gathered from various sources that may provide a deeper understanding of C# Generic:

  • Use generic instead of object or dynamic types whenever possible. Object requires boxing and unboxing processes, and dynamic requires runtime type resolution processes, both of which can lead to performance issues. Generic avoid these issues by removing the need for boxing, unboxing, and runtime type resolution, leading to better performance.

    Boxing is the process of converting a value type, such as int, float, or char, into an object type. Unboxing is the process of converting an object type into a value type.
    Runtime type resolution is the process of checking the actual type of a variable, determining its specific type at runtime, and performing operations based on this type to ensure type safety.
  • A generic method can be called without explicitly specifying the type parameter. For example, a generic method CheckAnswer<int>(int answer) can be invoked using CheckAnswer(1) instead of CheckAnswer<int>(1). The compiler automatically infers the type parameter based on the provided argument.

  • A reflection can be used to get information about generic type at the runtime.

    💡
    To learn more about C# Reflection, check out my post at C# Reflection - Last Night Codes.

Reference

  1. C# Generic – Microsoft

  2. C# Generic Constraints – Microsoft

  3. C# Generic Naming Guidelines - Microsoft

  4. Pros And Cons Using C# Generic – Microsoft

C#

Part 2 of 7

In this series, I’ll share the most important lessons and discoveries I’ve acquired about C#. From fundamental concepts to advanced features, discover how these lessons have sharpened my coding skills and how they can benefit to my projects.

Up next

C# Reflection

Introduction Hello all, today I back with another C# topic, and today I will share what i learned about C# Reflection. I hope with this article you will know more about C# Reflection and use it on your project. What It Is? Reflection is a powerful fe...

More from this blog

L

Last Night Codes

11 posts

Last Night Codes shares my journey through learning different programming languages and documenting my projects. Explore practical tips, insights, and personal coding experiences.