Index
1 - What are Generics in C#
Generics
is a feature provided by .NET
which allows us to create reusable code across multiple entities.
When we write generic code, we do so to make it compatible with any data type and thus "safe" for different types.
2 - Example of Generics in C#
The simplest way to demonstrate generics is by using sample code.
To do this, I’ll use code presented in a technical interview test, which fits perfectly for our purposes.
In that interview, I had to perform several API
calls and return the result if everything was correct. For example, there was an option get/{id}
which returned a Persona
object.
For that, I used a class called OperationResult
which contained 3 properties.
Bool Success
List<string> mensageList
Persona Persona
Wrapping objects within another can help if we have an application reading from our API. This way, we make things easier for the client.
public class OperationResult
{
public bool Success => !MessageList.Any();
public List<string> MessageList { get; private set; }
public Persona Persona { get; set; }
public OperationResult()
{
MessageList = new List<string>();
}
public void AddMessage(string message)
{
MessageList.Add(message);
}
public void SetSuccesResponse(Persona pers)
{
Persona = pers;
}
}
At the same time, we have another endpoint that must return a Coche
object.
public class OperationResultCars
{
public bool Success => !MessageList.Any();
public List<string> MessageList { get; private set; }
public Car Coche { get; set; }
public OperationResult()
{
MessageList = new List<string>();
}
public void AddMessage(string message)
{
MessageList.Add(message);
}
public void SetSuccesResponse(Car coche)
{
Coche = coche;
}
}
As we can see, both objects are practically identical, so we are repeating a lot of code. In our specific example, we are repeating 21 out of 23 lines of code, which means we are not following the "don’t repeat yourself" principle.
3 - Converting Our Code to Generic in C#
To convert our code to generic, we need to replace the differing code with its "generic" counterpart. Looking at the two previous examples, we only need to "merge" the Persona
and Car
types.
However, these types must still exist within our object, as we will need them.
For this, we convert the previous class as follows:
public class OperationResult <T>
{
public bool Success => !MessageList.Any();
public List<string> MessageList { get; private set; }
public T Response { get; set; }
public OperationResult()
{
MessageList = new List<string>();
}
public void AddMessage(string message)
{
MessageList.Add(message);
}
public void SetSuccesResponse(T obj)
{
Response = obj;
}
}
As we can see, there is only one main difference: we have now turned the Persona and Car types into the T type immediately after the class name, making our class generic.
By convention, any programmer working with generics will use the letter T
to indicate the type.
Finally, note that the T
type will accept any type, either one created by us such as the Persona
class or type, or a type such as string
.
3.1 - Multiple Types in a Generic Class in C#
Of course, we can implement more than one type in our generic class
. To do this, we must pass more than one type next to the class name.
public class OperationResult <T, U>
{
//Code
}
Still, by convention, when we introduce more than one type, we should use more than one letter to make things easier for programmers who come after us.
public class OperationResult <TEntrada, TSalida>
{
//Code
}
4 - Using a Generic Class
When we implement a generic class, we implement a type. That means, when we instantiate the generic class, we must indicate which type we’re going to use. To do this, we instantiate the variable as follows:
OperationResult<Car> optResult = new OperationResult<Car>();
Remember that T
inside our class accepts any type, so it works for the Car
class, Persona
class, etc.
5 - Generic Methods in C#
Classes are not the only parts that can be generic in our code; we can also make methods generic. To do this, we have two options
A - Generic Method in a Generic Class
First, we can have a method that receives a parameter T or returns a parameter T, which is perfectly valid, as shown in the previous example:
public void SetSuccesResponse(T obj)
{
Response = obj;
}
B - Generic Method in a Non-generic Class
If we have a non-generic class, we can create a method that accepts generic types. These are less common but are occasionally seen, especially in base classes.
To have a generic method in a non-generic class, we do it as follows:
public class Ejemplo{
public T GenericMethod<T>(T receivedGeneric)
{
return receivedGeneric;
}
}
We indicate <T>
after the method name.
And as we can see, we can also return the same type.
6 - Tips for Generics in C#
- We should use Generics to create reusable code and classes or methods that are not tied to specific types. But we need to be careful, because if a class will not be reused, we should NOT make it generic as it adds a lot of complexity to our code.
- We should use the letter T when we have only one type parameter, but if we have more than one, it should have a more descriptive name.
- Despite this, we should name parameters starting with
T
, to indicate to those reading our code that it represents a Type
7 - Constraints on Types
When declaring a generic class or method, we can extend the condition for the type of object we are going to use as a type.
To do so, we use the where T : {constraint}
clause.
public interface IExample {}
public class Example : IExample{}
public class EjemploGeneric <T>
where T : struct //value type
where T : class // reference type
Where T : new() //parameterless constructor
Where T : IExample //Specific interface
Where T : Example //a specific class
{
}
We can introduce constraints for all the types we use, and we can also include several constraints for a single type. For example, IExample
, new()
will require you to specify a class that implements IExample
and also has a parameterless constructor.
Conclusion
- We’ll use Generics as a way or technique to define multiple data types with a single variable.
- This allows us to create reusable code in a safe way, and it works with any type of data.
- Highly recommended to use generics as much as possible, but wisely, because while improving the quality of our code we can also add a certain difficulty.
If there is any problem you can add a comment bellow or contact me in the website's contact form