techmore.in

C# - Generics

Generics in C# allow you to define classes, interfaces, and methods with a placeholder for the data type. This enables you to create type-safe data structures and algorithms while avoiding code duplication. Generics provide flexibility and reusability by letting you define a class or method with a type parameter that is specified when the class or method is instantiated or called.

1. Generic Classes

A generic class allows you to define a class with a type parameter.

Syntax:

csharp
public class GenericClass<T> { private T data; public GenericClass(T value) { data = value; } public T GetValue() { return data; } }

Example:

csharp
GenericClass<int> intInstance = new GenericClass<int>(42); Console.WriteLine(intInstance.GetValue()); // 42 GenericClass<string> stringInstance = new GenericClass<string>("Hello"); Console.WriteLine(stringInstance.GetValue()); // Hello

2. Generic Methods

A generic method allows you to define a method with a type parameter.

Syntax:

csharp
public T GenericMethod<T>(T value) { return value; }

Example:

csharp
public T Echo<T>(T input) { return input; } int number = Echo(123); // 123 string text = Echo("Hello"); // "Hello"

3. Generic Interfaces

A generic interface defines a contract with type parameters.

Syntax:

csharp
public interface IGenericInterface<T> { T GetValue(); void SetValue(T value); }

Example:

csharp
public class GenericImplementation : IGenericInterface<int> { private int data; public int GetValue() { return data; } public void SetValue(int value) { data = value; } }

4. Constraints on Generics

Constraints allow you to restrict the types that can be used as arguments for generic type parameters.

Common Constraints:

  • where T : struct: Specifies that the type parameter must be a value type.
  • where T : class: Specifies that the type parameter must be a reference type.
  • where T : new(): Specifies that the type parameter must have a parameterless constructor.
  • where T : SomeBaseClass: Specifies that the type parameter must be a subclass of SomeBaseClass.
  • where T : ISomeInterface: Specifies that the type parameter must implement ISomeInterface.

Example:

csharp
public class ConstraintExample<T> where T : new() { public T CreateInstance() { return new T(); // Requires T to have a parameterless constructor } }

5. Generic Collections

C# provides several generic collections in the System.Collections.Generic namespace, such as List<T>, Dictionary<TKey, TValue>, and Queue<T>.

Example with List<T>:

csharp
List<string> names = new List<string> { "Alice", "Bob", "Charlie" }; names.Add("Dave"); foreach (string name in names) { { Console.WriteLine(name); // Prints each name }

Example with Dictionary<TKey, TValue>:

csharp
Dictionary<string, int> ages = new Dictionary<string, int> { { "Alice", 30 }, { "Bob", 25 } }; ages["Charlie"] = 35; foreach (var entry in ages) { { Console.WriteLine($"{entry.Key}: {entry.Value}"); // Prints name and age }

6. Covariance and Contravariance

Covariance and contravariance apply to generic interfaces and delegates and allow for more flexibility in type assignment.

  • Covariance allows a method to return a more derived type than originally specified.
  • Contravariance allows a method to accept parameters of a less derived type.

Example with Interfaces:

csharp
public interface ICovariant<out T> { T GetValue(); } public interface IContravariant<in T> { void SetValue(T value); } public class StringCovariant : ICovariant<string> { public string GetValue() { return "Hello"; } } public class ObjectContravariant : IContravariant<object> { public void SetValue(object value) { Console.WriteLine(value); } }

Summary

Generics in C# provide a way to create reusable and type-safe code by defining classes, interfaces, and methods with placeholder types. They enhance code flexibility and maintainability by allowing you to work with different data types without sacrificing type safety. Constraints, generic collections, and concepts like covariance and contravariance further extend the capabilities and flexibility of generics. Understanding and using generics effectively can significantly improve your coding efficiency and reduce code duplication.