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
  }
}

Limiting Generics

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();
  }
}

See Also

⚠️ **GitHub.com Fallback** ⚠️