Generics.md - brainchildservices/curriculum GitHub Wiki
In C#, generic means not specific to a particular data type.
C# allows you to define generic classes, interfaces, abstract classes, fields, methods, static methods, properties, events, delegates, and operators using the type parameter and without the specific data type.
A type parameter is a placeholder for a particular type specified when creating an instance of the generic type.
Why do we need Generics?
We need to write a program to compare two numbers.
So we write a method that takes integer parameters to compare the integer numbers and return the result. We will use the built-in Equals method that's available for all objects for comparing the numbers.
using System;
public class Program
{
public static void Main()
{
Console.WriteLine(Compare(1, 2));
}
public static bool Compare(int a, int b)
{
if (a.Equals(b))
return true;
else
return false;
}
}
We need to compare two float values. So we create another Compare method that takes two float parameters.
using System;
public class Program
{
public static void Main()
{
Console.WriteLine(Compare(1, 2));
Console.WriteLine(Compare(1.1f, 1.1f));
}
public static bool Compare(int a, int b)
{
if (a.Equals(b))
return true;
else
return false;
}
public static bool Compare(float a, float b)
{
if (a.Equals(b))
return true;
else
return false;
}
}
It is method overloading that is helping us to create different methods with the same name as they all have different method signatures.
So if we look at our program we are having to create different methods for the different datatype. But every method is implementing the same logic.
This is where the Generics comes to our help.
So instead of specifying the parameters in the method signature, we can replace return type and type of the parameter with placeholder (type parameter) T most often is used as type parameter). And to show that the method uses placeholder, we would put the placeholder in angle brackets after the Method name.
using System;
public class Program
{
public static void Main()
{
Console.WriteLine(Compare<int>(1, 2)); //2. When we call the method we would specify the parameter types
Console.WriteLine(Compare<float>(1.1f, 1.1f));
}
public static bool Compare<T>(T a, T b) //1. Replace the parameter types with T and specifying <T> after the brackets
{
if (a.Equals(b))
return true;
else
return false;
}
}
3 steps to create Generic methods:
- Instead of parameter type, specify T
- After Method name put
- When calling the method, put the datatype that you want to use. Eg?
Generic Class
Generic classes are defined using a type parameter in an angle brackets after the class name.
public class ClassName<T>
{
ClassBody
}
We can specify the data type the class uses when we create object of the class. ClassName ObjectName=new ClassName();
Example:
using System;
//Declaring class
public class Print<T> //ClassName is followed by type parameter in angle brackets
{
}
public class Program
{
public static void Main()
{ //Creating an object
Print<int> newsPaper = new Print<int>(); //Specifying the datatype in angle brackets after the className.
}
}
A method declared with the type parameters for its return type or parameters is called a generic method.
using System;
public class Print
{
public void Numbers<T>(T a, T b) // Specifying parameter as type parameters and adding type parameter in angle brackets after the method name
{
Console.WriteLine("The numbers are :{0}, {1}", a, b);
}
}
public class Program
{
public static void Main()
{
Print newsPaper = new Print();
//Specifying the datatype in angle brackets after the method name, when the method call is made
newsPaper.Numbers<int>(10, 20);
newsPaper.Numbers<float>(10.09f, 20.34f);
newsPaper.Numbers<double>(10.0945, 20.34467);
}
}
A generic class can include generic fields.
using System;
public class Print<T> //Creating Generic class with T type parameter
{
public T variable; //Declaring a filed with type parameter, the data type of the field would be determined when the object is created
public class Program
{
public static void Main()
{
Print<int> number = new Print<int>(); //Creating object with int as the type paramater
number.variable = 10; //So the variable is able to store integer values
Print<string> letter = new Print<string>(); //Creating object with string as the type paramater
letter.variable = "Joseph"; //So the variable is able to store string values
}
}
Generic Fields cannot be initialized.
using System;
public class Print<T>
{
public T variable=100; //Generic fields cannot be initialized
}
public class Program
{
public static void Main()
{
vPrint<int> number = new Print<int>();
number.variable = 10;
Print<string> letter = new Print<string>();
letter.variable = "Joseph";
}
}
We can have multiple type parameters. We need to separate the type parameter by commas.
using System;
public class GenericClass<T1, T2> //T1 and T2 type parameters in Generic class separated by commans.
{
public void GenericMethod(T1 a, T2 b)
{
Console.WriteLine(a);
Console.WriteLine(b);
}
}
public class Program
{
public static void Main()
{
GenericClass<int, double> gC1 = new GenericClass<int, double>(); //Datatypes separated by commans in class instantiation
gC1.GenericMethod(23, 34.567);
GenericClass<string, double> gC2 = new GenericClass<string, double>(); //Datatypes separated by commans in class instantiation
gC2.GenericMethod("John", 34.567);
}
}
Notes:
- If the class is Generic, specify type parameters after the className and when instantiating the class, specify the datatype after the className in angle brackets. No need to put type parameters in angle brackets after the MethodName or other class members.
using System;
public class GenericClass<T1> //T1 in angle bracket after the classname as the class is Generic
{
public void GenericMethod(T1 a) //No Angle brackets after the method name as the class is Generic
{
Console.WriteLine(a);
}
}
public class Program
{
public static void Main()
{
GenericClass<int> gC1 = new GenericClass<int>(); //Datatypes separated by commas in class instantiation
gC1.GenericMethod(23); //No Angle brackets after the method name
GenericClass<string> gC2 = new GenericClass<string>();
gC2.GenericMethod("John");
}
}
- If the class is Non-Generic. specify type parameter in anglebrackets after the membername. And specify the datatype after the membername in angle >brackets when the member call is made.
using System;
public class NonGenericClass
{
public void GenericMethod<T1>(T1 a)
{
Console.WriteLine(a);
}
}
public class Program
{
public static void Main()
{
NonGenericClass gC1 = new NonGenericClass();
gC1.GenericMethod<int>(23);
NonGenericClass gC2 = new NonGenericClass();
gC2.GenericMethod("John");
}
}
- Reusability: You can use a single generic type definition for multiple purposes in the same code without any alterations. For example, you can create a generic method to add two numbers. This method can be used to add two integers as well as two floats without any modification in the code.
- Type Safety: Generic data types provide better type safety, especially in the case of collections. When using generics you need to define the type of objects to be passed to a collection. This helps the compiler to ensure that only those object types that are defined in the definition can be passed to the collection.
- Performance: Generic types provide better performance as compared to normal system types because they reduce the need for boxing, unboxing, and typecasting of variables or objects.
Exercise:
-
Create class Students. Students have two properties age and mark. Both properties are Generic. Create constructor for the class Students to pass value to the properties. Create method Print that returns a string that uses both the properties.
In Main method pass values to the properties and call the method Print and display the returned string from the method. -
Create a Generic class Person. Person has two properties name and address(Type parameter T1). Two other properties: age and year of birth (Type parameter T2). All 4 properties are Generic. Create a constructor for the class Person to pass value to the properties. Create method PrintEmployee. PrintEmployee has 2 parameters(Type parameter T1): salary and employee ID. The method Prints the parameter values.
In Main method pass values to the properties and call the method PrintEmployee.
References:
https://www.geeksforgeeks.org/c-sharp-generics-introduction/
https://www.youtube.com/watch?v=hmgDvQ9e_R4
https://www.tutorialsteacher.com/csharp/csharp-generics