Generics - mcbride-clint/DeveloperCurriculum GitHub Wiki
Generics are a very useful tool in creating dynamic and reusable code.
It allows a Type of a class or function to be passed in like a parameter.
The Generic Type parameter is passed in between angle brackets <T>
One of the most famous examples is List<T>
. See Collections.
When declaring a variable of Type List<T>
, a developer would provide a Type for T
so that the List
will only then work with that Type.
// Declare a List of strings
List<string> strings = new List<string>();
// List can only accept strings
strings.Add("Hello World");
// Other types will show as an error
strings.Add(123);
// Any Type can be used
List<User> users = new List<User>();
Generics can be used on functions and class definitions as well.
// When declaring a class with one or more Generic Types, that Type will be used throughout the class.
public class Analyzer<T> {
public List<T> Results { get; set; }
public void LoadData<T>(List<T> items) {
// Analyze items
}
}
// Multiple Generic Types can be provided
public class Analyzer<TInput, TOutput> {
public List<TOutput> Results { get; set; }
public void LoadData<TInput>(List<TInput> items) {
// Analyze items
}
}
By default when creating Generic code, the compiler will enforce the lowest common denominator which would be object
.
.Net allows you to place a constraint on the allowable Types.
This can allow you to have greater functionality within the Generic code that you write.
The most functionality can be gained by constraining to a parent class or an Interface.
public interface IPerson {
string FirstName { get; set; }
string LastName { get; set; }
string FullName();
}
public class Employee : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName() {
return LastName + ", " + FirstName;
}
}
public class Manager : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName() {
return LastName + ", " + FirstName + "(Manager)";
}
}
// Can now accept anything that implements IPerson, either Employee or Manager
public class PersonProcessor<T> where T : IPerson
{
// Generic Code now has access to IPerson specific functionality
public string GetName<T>(T person){
// The generic code will now call the FullName function that belongs to the Type passed in.
return person.FullName();
}
}
- Microsoft Docs - https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/
- Pluralsight - C# Generics (Scott Allen) - https://app.pluralsight.com/library/courses/csharp-generics/table-of-contents
- Dapper