Generics in C# .NET With Examples

Generics allow you to reuse the same code (class or method) with different data types. It refers to a generalized version of something rather than a specialized version.

In this article, we are going to talk about the use of Generics in C# with multiple examples.

Generics in C#
Generics in C#

C# Generics

Generics were first introduced in the C# version 2.0. Generics make our code type independent. This means that our code is not limited to a specific data type as it allows us to reuse our class or method with different data types.

  • A generic type in C# is declared after the type name in angle brackets <>, for example. Type_Name<T> where T is a type parameter that indicates any type can be accepted. The angle brackets are used to declare a class, Interface, or method as a generic type.
  • The <T> type parameter is used to decouple the Interface, class, method, field, property, event, operator, and delegate from specific data types.
  • Generics in C# belong to System.Collections.Generic namespace which contains several generic-based classes.

For example, List in C# is a generic collection that can be used with different data types, such as List<int>List<float>List<string>, or List<Employee>

<T> is nothing more than a placeholder or blueprint for the data type. The compiler will replace it with the actual type during runtime.

Note: It is not always required to use T as a type parameter. The Generic type parameter name can be anything as per your requirements such as T, TKey, TValue, etc.

Why do we use generics in C#?

  • C# Generics provide code reusability as the same code can be reused for different data types.
  • Generic has a performance advantage because it eliminates the possibility of boxing and unboxing.
  • Generics are most commonly used to create generic collection classes.
  • We can put constraints on generic classes so that only the selected types can be used by the client.
  • Generic types can be used to maximize code reusability, type safety, and performance.
  • Generics provide a type-safe approach for creating collections for both reference and value types without fear of breaking their generality.
  • If you try to use a data type other than the one specified in the definition, you will get compile time error.
  • In Generics there is no need for casting for accessing the elements from the collection
  • Generics allow you to add parameters to your types much like you would add parameters to your methods to extend their generality.

C# Generic class example

A generic class can be created by specifying an actual type in <> angle brackets. The following is an example to create a generic class in C#.

using System;
namespace Generic
{
    // Generic Class
    class MyGenericClass<T>
    {
        public MyGenericClass(T parameter)
        {
            Console.WriteLine(parameter);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
          MyGenericClass<string> genericClassString = new MyGenericClass<string>("Hello");
          MyGenericClass<int> genericClassInt = new MyGenericClass<int>(100);
          MyGenericClass<float> genericClassFloat = new MyGenericClass<float>(100.5f);
          MyGenericClass<Char> genericClassChar = new MyGenericClass<Char>('A');
            Console.ReadLine();
        }
    }
}

Generics in C# class output
The output of the above program.

C# Generic method example

A generic method is a method that is defined with a type parameter using angle <> brackets.
In the following example, we can pass any type of parameter to the generic method.

Generic method in C#
Generic methods in C# example.
using System;
namespace Generic
{ 
    class MyClass
    {
        //Generic Method
        public T MyGenericMethod<T>(T parameter)
        {
            return parameter;
        }
        
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyClass myClass1 = new MyClass();

            string str = myClass1.MyGenericMethod<string>("Hello");  
            
            int number = myClass1.MyGenericMethod<int>(100);

            Console.WriteLine(str);
            Console.WriteLine(number);
            Console.ReadLine();
        }
    }
}

//Output:
//Hello
//100

If you observe the above code, we call our generic method (MyGenericMethod) with different types of arguments based on our requirements.

C# Generic field example

In the following example, we are creating MyGenericClass class, Here, we need to specify the type and the compiler will assign that type to T.
In this sample code, we are using string as the data type. Once we create an instance of the MyGenericClass, then we will call the generic field. As we have specified the T as a string while creating the class instance. So, we do not need to specify the type again when calling the class members.

using System;
namespace GenericsExample
{
    //Here T specifies the Data Type of class and field
    class MyGenericClass<T>
    {
        //Generic field/Variable    
        public T GenericField; 
             
    }

    class Program
    {
        static void Main()
        {
            MyGenericClass<string> myGenericClass = new MyGenericClass<string>();
           string value =  myGenericClass.GenericField = "Generic Field";

            Console.WriteLine(value);
            Console.ReadKey();
        }
    }
    // Output: Generic Field
}

Generic Type Constraints

In generic the where clause restricts the types that are used as arguments for the type parameter during the instantiation of the generic type.
You will get a compile-time error if you use a type that doesn’t satisfy a constraint.

Generic constraints in C# are applied by using the  where  keyword.

Generic type constraints
C# Generic Constraints

The following is the list of various types of generic constraints in C#.

C# Generic ConstraintsDefinition
where T: classThe type argument must be a reference type. This constraint can be applied to any class (non-nullable), interface, delegate, or array type in C#.
where T: class?The type argument must be a nullable or non-nullable reference type like class, interface, delegate, or array type.
where T: new()The type argument must be a reference type with a public parameterless (default) constructor. It cannot be combined with struct and unmanaged constraints.
When used together with other constraints like class, the new() constraint must be specified last (example: where T: class, new()).
where T: structThe type argument must be non-nullable value types such as primitive data types int, double, char, bool, float, etc.
The struct constraint can’t be combined with the unmanaged constraint.
where T : <interface name>The type argument must be or implement the specified interface. Also, multiple interface constraints can be specified.
where T: UThe type argument supplied must be or derive from the argument supplied for U. In a nullable context, if U is a non-nullable reference type, T must be a non-nullable reference type. If U is a nullable reference type, T may be either nullable or non-nullable.
C# Generic Constraints

The generic types exist in System.Collections.Generic namespace. Some of the existing generic classes and interfaces are listed below:

Please read my previous article where I discussed the Generic Delegate in C#.

I hope you enjoyed this post and found it useful. If you have any doubts, please post your feedback, questions, or comments.

References MSDN: Generic Classes and Methods

Recommended Articles:

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments