[C# Generics] Generic Types – Basics

When we talk about Generics, we usually means the type-defined collections such as List<T>, or Dictionary<TKey, TValue>. It is true that most generic classes are collections and we do not need to create custom generic classes. But understanding general syntax to declare/use generic types and methods will help you use generic collections fully.           


1. Generics

Generics allow you to reuse algorithms or patterns for different data types. I summarized the benefits people are talking about generics.

  • Compile-time type checking
  • A strongly typed programming model
  • No boxing/unboxing – performance boost
  • No cast to object and back to the original type
  • More concise and readable code due to the lack of casting and the specified type name
  • Coding assistant through IntelliSense


2. Generic Classes

When we define a generic class, you need to specify a “Type Parameter“. The type parameter is  a placeholder.  The name of type parameters should include a “T”  prefix. The descriptive name can be helpful, but in many cases, just <T> might suffice.

Let’s define the “Compare<T>” class to compare any two numbers.

public class Compare<T> { }


3. Generic Interfaces and Structs

Generics can be used with interfaces and structs. The LINQ is associated mainly with the Interface “IEnumerable<T>“.


4. Constructors in Generic Classes

A constructor in a generic class does not require the type parameter. You can use the type parameter as a parameter type.

public class Compare<T>
    public Compare(T x) { }

But what if you want to specify the default value of the type? You even do not know what type it will be. The solution is the “default” keyword.

public Compare()
    Value1 = default(T);


5. Generic Methods

In general, methods and properties are not generic even in the generic class.  But you can specify the type parameter on methods (Generic Methods) to make them generic. Generic Methods does not need to be used only within a generic class. They can be used in any classes. Usually generic method is used in the static class, which does not need to be generic.


6. Constraints

Let’s finish the “Compare<T>” class.

public class Compare<T>
    public T Value1 { get; set; }

    public Compare(T x)
        Value1 = x;

    public bool IsBiggerThan(T val)
        return Value1.CompareTo(val) > 0;

The problem is that the code is not compiled because all types do not have the “CompareTo()” method. Only classes implements “IComparable<T>” will have the method. You do not want to cast the variable whenever it is required to be a certain type. If you need to cast, why we use generics in the first place?

You can provide <T> with constraints to limit <T> to be a specific type (interface or a subclass).

The “where” keyword is used to specify the constraints to the type parameter.

public class Compare<T> where T : IComparable<T> { }

  • Base class
  • Interface
  • struct” or “class”  – value type or reference type
  • new()” – requires a parameter-less constructor
public class Nullable<T> where T : struct { }
public class MyDictionary<TKey, TValue>
  where TKey IComparable<TKey> where TValue : EntityBase, new()
{ }


7. Rules for constraints

  • Different type parameters require a separate “where” statement.
  • Constraints cannot be both “struct” and “class
  • Constructor constraints are allowed only for a default constructor
  • struct” or “class” must be the first constraint
  • new()” must be the last constraint
  • You can provide multiple interfaces or base classes but they are combined as a “AND” relationship. You cannot specify any relationship between them.

– Valid Constraints

public class Sample<T> where T : class, IComparable<T>, new() { }
public class Sample<T, K> where T : IComparable<T> where K : class { }

– Invalid Constraints

public class Sample<T, K> where T : IComparable<T>, K : class { } // need where for "K"
public class Sample<T> where T : IComparable<T>, class, new() { } // class should be the first
public class Sample<T> where T : new(), IComparable<T> { } // new must be the last
public class Sample<T> where T : IComparable<T>, new(T) { } // only default constructor

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s