Understanding Generics in C#
When I started my coding journey in C# and learned to create projects, I wondered if we could define classes and methods without specifying exact data types.
I got this answer when I came across Generics. This powerful feature in C# allows devs exactly what I was wondering.
Web developers must always try to reusable code instead of repeating the same code multiple times — saves time, and code becomes efficient and maintainable.
What are Generics?
So technically, generics is like a placeholder where you can define your classes, methods, or even interfaces without worrying about the type of the code until it is instantiated or invoked.
What’s best thing is, you can work with different data types without duplicating your code.
For example, consider a non-generic ArrayList:
ArrayList list = new ArrayList();
list.Add(1);
list.Add("hello");
list.Add(3.14);
What happens here is that ArrayList will allow you to store any data type — which is flexible, but what you need to understand here is that it is prone to runtime errors.
Do you know what will happen if you try to retrieve a value of the wrong type? — It will result in an exception. And this is an unwanted situation that any dev wants to tackle.
In such cases, we can take the help of generics. It eliminates this problem by ensuring type safety at compile time.
List<int> list = new List<int>();
list.Add(1);
// list.Add("hello"); // This will cause a compile-time error.
So as you can see, I have used int type and if I try to add a string type into this list, I would receive a compile-time error.
Let’s look at some advantages generics has to offer:
Generic Classes
A generic class allows you to define a class with type params.
Here’s how it can be defined:
The T here acts as a placeholder and makes the class reusable for any data type. Isn’t that great?!
The _value is a private field of type T. It will hold the value provided during the object’s creation.
Finally in the Main(), I have used two data types but reused the same GetValue(). It creates an instance of GenericContainer and uses multiple data types to demonstrate code reusability.
Output
Generic Methods
Methods with type parameters are generic methods. The parameters are specified when the method is called.
Here I have taken a classic swap example that demonstrates the usage of generic methods.
The Swap<T>` indicates a generic method and can operate on any data type.
ref T a and ref T b — both parameters are passed by reference (ref keyword). This means the method modifies the original variables rather than working with copies.
Output
Built-in Generic Types
Did you know .NET Framework already provides several generic types and classes?
领英推荐
Generic Interfaces
Just like normal interfaces, a generic interface also defines a contract for classes. Any class that inherits this interface must use methods declared in it.
Here’s what it would look like:
Here, IRepository<T> is an interface that mandates all the classes that inherit this interface to implement all the methods declared in it.
In other words, this interface defines a contract for classes that inherit this.
The data type is flexible because of its <T> type.
Output
Constraints in Generics
C# allows you to use constraints that allow restriction to specify certain types while instantiating generic types.
Using constraints, when we create a new instance of a generic type we can restrict what types we want to substitute for type parameters.
If we try to substitute a type that does not comply with the constraint we can expect a compile-time error.
We specify constraints using the where clause. No, don’t worry. This is not SQL class ??
Pay attention to the description given.
A simple example of each that would help you understand how it is declared
Class
Struct
Default constructor using new()
BaseClass
Interface
Limitations
Despite the generic’s flexibility, it does have some limitations.
List<object> list = new List<string>();
Is still invalid even though the string is derived from an object — strange, but true.
public T Add<T>(T a, T b) where T : /* What to write here? */
{
return a + b; // This throws error because '+' operator is not defined for T.
}
Ending Note
Make use of such features that C# provides to enhance your code and write efficient pieces of code. By understanding generics, you can reduce code duplication and improve app performance.
Despite its limitations, devs must use generics depending on their project requirement.
Thank you for reading! ??
Application Support Specialist at Tata Consultancy Services
1 个月Very helpful