Learning to Code — Part 11: Generics

OK, so let’s bring this baby in for a landing!

GENERIC METHODS

According to the SoloLearn app, generics allow the reuse of code across different types. To demonstrate this, let’s first declare a method that swaps the values of two parameters:

static void Swap(ref int a, ref int b) {
int temp = a;
a = b;
b = temp;
}

As a reminder for myself, I decided to look up ref as it was the only thing in the above code that I couldn’t remember. Over on the C# Corner site, within an article called ref Keyword in C#, it became clearer to me by comparing the following original and changed code.

Original:

public static void GetData(int a) {
a = a + 999;
Console.WriteLine(“Value inside method is: “ + a);
}
static void Main(string[] args) {
int a = 4;
Console.WriteLine(“Value before method is: “ + a);
GetData(a);
Console.WriteLine(“Value after method is: “ + a);
Console.ReadKey();
}

When the code above is executed, starting within the Main method:

  • An integer-based variable called a is declared, and is assigned a value of 4.
  • Value before method is: 4 is then printed to the screen.

This is important, in other words, before the GetData method is called, a equals 4.

  • Next, the GetData method is called, and the current value of a, which is 4, is sent.
  • The variable a is then set as equal to the variable a plus 999, or a = 4 + 999, or a = 1003.
  • Value inside method is: 1003 is then printed to the screen.

Now, this is also important, in other words, within the GetData method, a equals 1003.

  • Finally, back to the Main method, Value after method is: 4 is then printed to the screen.

In other words, although the value of a changed within the GetData method, that change does not translate back to the location from which it was called. So, a is back to equaling 4.

That code is without the ref keyword. Next, we change the code of the GetData method.

Changed:

public static void GetData(ref int a) {
a = a + 999;
Console.WriteLine(“Value inside method is: “ + a);
}

When executed, everything that happened originally, happens again EXCEPT that the 1003 value is sent back to the calling location, so the last line of code will now print Value after method is: 1003 to the screen.

So, back to generics, and the code once again:

static void Swap(ref int a, ref int b) {
int temp = a;
a = b;
b = temp;
}

At the moment, the Swap method only works for integers. If we wanted it to work for other types, we’d need to overload it for all types we wanted to use with it. In other words, we’d create a whole bunch of Swap methods, each one for a specific type. Generics give the ability to deal with that by defining a generic type:

static void Swap<T>(ref T a, ref T b) {
T temp = a;
a = b;
b = temp;
}

In the code above, T is the name of the generic type. Apparently you can name it anything, but T is a common practice. The <T> indicates that you’ll be defining a generic type. In the parentheses, ref T a and ref T b, refers to the fact that two parameters of type T will be received. We also have to write T temp to make sure that the variable called temp is also of type T.

Next, within the Main method where the generic method will be called, we need to specify the type that will be used each time the generic method is called:

static void Main(string[] args) {
int a = 4, b = 9;
Swap<int>(ref a, ref b);
string x = “Hello”;
string y = “World”;
Swap<string>(ref x, ref y);
}

So, when the Swap method is called the first time, we write Swap<int> to tell it that we’re sending an integer-based value. When we call it the second time, we write Swap<string> to tell it that we’re sending a string-based value. In reality, as a result of indicating this, the T in the generic method that gets replaced with the int or string.

As I’m proofreading this, I’m realizing that this last point would have been a good one for me to remember as I went along.

As an efficiency, the app mentions that if you don’t specify the type when calling the generic method, the C# compiler will use the type based on the arguments being passed. Also, you can use more than one generic parameter with a single method. The following would take in two generic types: Func<T, U>.

GENERIC CLASSES

The generic types used in methods can also be used in classes. You’d use it in the case where a collection of items, despite their individual types, will have basically the same operations performed on them.

One type of collection is called a stack. Items are pushed, or added to the collection, or (and I swear I’m not making this up) popped, or removed from the collection.

They also mention that…

…a stack is sometimes called a Last In First Out (LIFO) data structure.

First, let’s establish the generic class and it’s generic methods:

class Stack<T> {
int index = 0;
T[] innerArray = new T[100];
     public void Push(T item) {
innerArray[index++] = item;
}
     public T Pop() {
return innerArray[ — index];
}
     public T Get(int k) { return innerArray[k]; }
}

This generic class, called Stack, will store elements in an array. The generic type called T is the type of the array, and the type of the parameter for the Push method, and the return type for both the Pop and Get methods. Next we can instantiate objects of the generic class:

Stack<int> intStack = new Stack<int>();
Stack<string> strStack = new Stack<string>();
Stack<Person> PersonStack = new Stack<Person>();

In the code above, a new object called intStack is instantiated, which is of the generic class type Stack, and has a data type of int. Also, a new object called strStack is instantiated, which is also of the generic class type Stack, but has a data type of string.

The last line instantiates a new object called PersonStack, which is of the generic class type Stack, but has a custom defined type called Person. They also state…

In a generic class we do not need to define the generic type for it’s methods, because the generic type is already defined on the class level.

While I generally understand the concept of what’s being done, I really don’t see what is literally occurring when new objects of the Stack class are instantiated. Also, when I type the code into Visual Studio, it has a problem with the Person type as it says:

The type or namespacePerson’ could not be found…

Finally, I don’t understand what is being referred to within that last thing they mention, about not needing to define the generic types for the methods within a generic class.

Google…here I come!!!

I found an article on TutorialsTeacher.com called Generics in C# and, while the concept didn’t “click” from this either, there’s an image that is proceeded by the following sentence:

The following figure illustrates how the compiler will replace T with int in MyGenericClass.

In other words, the T gets replaced with the data type being sent. So, in our code, when we instantiate the Stack object with the int type, the generic class called Stack will replace the T with int, as in the following:

class Stack<int> {
int index = 0;
int[] innerArray = new int[100];
     public void Push(int item) {
innerArray[index++] = item;
}
     public int Pop() {
return innerArray[ — index];
}
     public int Get(int k) { return innerArray[k]; }
}

In other words:

  • A new object of the Stack class is instantiated called intStack (and indicates that it will be of the data type int).
  • Within the Stack class which, in this case, is integer-based, a new integer-based variable is declared called index, and set with the value 0.
  • Next, an integer-based array called innerArray is instantiated with a capacity of holding 100 integer values.
  • The Push method is then executed and simultaneously declares an integer-based variable called item.

DO NOT READ THE FOLLOWING! IT IS INCORRECT, BUT I DIDN’T REALIZE THAT UNTIL JUST AFTER THE “BOXED TEXT”. SKIP TO THAT!

Inside it, within the array called innerArray, each index position gets a value, one higher than the value of the previous index position. In other words, the 0 index position, called index, is set equal to the current value of index, which is 0, plus 1. That translates into index = index + 1, or index = 0 + 1, or index = 1, or the 0 index position = 1.
The next index position, the 1 index position, again called index, then gets the next current value of index, which is 1, plus 1. That translates into index = index + 1, or index = 1 + 1, or index = 2, or the 1 index position = 2.
The next index position, the 2 index position, again called index, then gets the next current value of index, which is 2, plus 1. That translates into index = index + 1, or index = 2 + 1, or index = 3, or the 1 index position = 3.
This continues until all index positions have values up to 100. Also, each time an index position gets a value, that value is also assigned to the integer-based variable called item. So, the Push method is adding values to the array called innerArray.

START READING AGAIN HERE…

I was trying to understand what happens next, because nothing in the SoloLearn app shows the Push, Pop or Get methods being called. In other words, while I understand what happens when each method is called (as described previously in my explanation of what happens when the Push method is called), the instantiation of a new object of Stack type doesn’t actually call those methods. So, it looks like all that happens is the an integer-based variable called index is declared and assigned the value 0. Then, a new integer-based array called innerArray is instantiated with a capacity of holding 100 integer values…and that’s all that happens!!

I Googled a bit more and landed on another article on Guru99 called C# Stack with Example. In it, above a code sample that does that same instantiation, there’s the simple title, Declaration of the Stack. In other words, I was right, those other methods within the Stack class ARE NOT called (and therefore NOT EXECUTED) when the new object called intStack, of Stack class, is instantiated.

To take it further, the article describes that if you wanted to push or add an item to the new array that gets created, you’d need to have code that calls its method, which looks like this:

intStack.Push(element)

…where element is an integer-based value. If you wanted to pop or remove an item from the new array that gets created, you’d need to have code that calls its method, which looks like this:

intStack.Pop(element)

Finally, you can also get a value from the new array that gets created, you’d need to have code that calls its method, which looks like this:

intStack.Get(element)

Alright, now I’ve got it!! Skipping to the last sentence:

In a generic class we do not need to define the generic type for it’s methods, because the generic type is already defined on the class level.

This means that we don’t need to define the generic type for the Push, Pop and Get methods because, by adding the T, they get it from the first line of code of the Stack class, which is class Stack<T>.

The only last thing that still is weird is the fact that Visual Studio doesn’t like the custom type defined as the Person type. For the moment, I’m going to trust that what they’re saying is true, and hope they re-address it later on.

As you read what I write for the next section, you’ll understand when I say it would have been nice in the last section, to explain that the calling of the methods within the generic class will be explained in the next section.

The app explains that methods within a generic class are called in the same way as any other object:

Stack<int> intStack = new Stack<int>();
intStack.Push(3);
intStack.Push(6);
intStack.Push(7);
Console.WriteLine(intStack.Get(1));

The first line of the code above is the same as before, which:

  • Causes an integer-based variable called index to be created, and given a value of 0.
  • Then, a new integer-based array called innerArray is instantiated and configured to hold 100 integer values.
  • Back to the next line after the intStack object was created, the Push method is called and sent a value of 3.
  • Within the Push method, an integer-based variable called item is declared and given the value that was sent, which was 3.
  • Next, the 0 index position is set to be equal to the current value of index, which is 0, and into that position goes the current value of item, which is 3.
  • The value of index is now incremented from 0 to 1.
  • Back to the location where the Push method was called and sent the value of 3, the Push method is called again, sending the value 6, which results in index position 1, of the array called innerArray, being assigned the value of 6.
  • Back to the location where the Push method was called and sent the value of 6, the Push method is called again, sending the value 7, which results in index position 2, of the array called innerArray, being assigned the value of 7.
  • Back to the location where the Push method was called and sent the value of 7, the Get method is called, specifically looking for the value at index position 1 within the array that was created when the intStack object was instantiated.
  • Within the Get method, and integer-based variable called k is declared and assigned that incoming value of 1.
  • It will then return to the calling location, the value of the element at index position k, or index position 1, of the array called innerArray, which is 6.
  • Back to where it was called, that value, 6, is printed to the screen.

OK, I not only now understand what’s going on, I also understand that my previous attempt was incorrect (the text in the gray box above). The reason was because I was incrementing the value of index first. As a result, I had the value in the 1 index position as 3.

COLLECTIONS

Inasmuch as we were talking earlier about creating new collections of items, there are a number of generic collection classes that can be used, which are useful for storing and manipulating data. To use them, however, you need to make sure that the System.Collections.Generic namespace is loaded into your program. Luckily, by default, new programs in Visual Studio include this line:

using System.Collections.Generic;

One of those generic collection classes is List:

List<string> colors = new List<string>();
colors.Add(“Red”);
colors.Add(“Green”);
colors.Add(“Pink”);
colors.Add(“Blue”);
foreach (var color in colors) {
Console.WriteLine(color);
}

The code above instantiates a new string-based list called colors. It then adds to that list Red, Green, Pink and Blue. Next, it iterates through each item (using the foreach loop) within the list called color, and prints the value to the screen, each on it’s own line. The Add method is just one built-in to the List class (as we saw, it adds an element to the List). Additional methods include:

  • Clear — removes all elements from the List.
  • Contains — determines whether the specified element is contained in the List.
  • Count — returns the number of elements in the List.
  • Insert — adds an element at the specified index.
  • Reverse — reverses the order of the elements in the List.

The app then asks the question that was in my head, which was, why should we use Lists instead of arrays:

Because, unlike arrays, the group of objects you work with in a collection can grow and shrink dynamically.

Ahh, yes, we’re not pre-specifying the size of the List, whereas we do with an array.

Before I go through the last section, which is about generic collection types, it’s worth mentioning that the page doesn’t have any examples for each of those methods. I looked them up myself and added them below each one in the same format as the List example above:

  • List<T> — represents a list of objects that can be accessed by index. Provides methods to search, sort, and modify lists (see the List example above).
  • Dictionary<TKey, TValue> — represents a collection of key/value pairs that are organized based on the key.
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add(“cat”, 2);
dictionary.Add(“dog”, 1);
dictionary.Add(“llama”, 0);
dictionary.Add(“iguana”, -1);
foreach (KeyValuePair<string, int> item in dictionary) {
Console.WriteLine(“{0}, {1}”, item.Key, item.Value);
}

Sources:

For a Dictionary, you have to give two values: a string-based key, which is the word item above; and an int-based value, which is the number item above. Within the foreach loop, you need to include the keyword KeyValuePair so that you can then pull both values. Finally, to print them to the screen, use the dot syntax to select the Key value of item, followed by the Value value of item.

  • Queue<T> — represents a first in, first out (FIFO) collection of objects.
Queue<int> collection = new Queue<int>();
collection.Enqueue(5);
collection.Enqueue(6);
foreach (int value in collection) {
Console.WriteLine(value);
}

This is similar to the List collection, except that Queue handles the elements in the order that they were received.

Sources:

  • DotNetPerls — Queue
  • Stack<T> — represents a last in, last out (LIFO) collection of objects (we went over this above with our first example of generic classes).

The app goes on to say that you…

Choose the type of collection based on the data you need to store and the operations you need.

The first question of the section quiz asks you to fill in the blanks, and results in the following:

static T Swap<T>(ref T a, ref T b) {
T temp = a;
a = b;
b = temp;
     return a;
}

In my attempt, I had reversed the T and <T> on the first line, which was wrong. I did that because up above in this article, the code I wrote had void instead of T, so I didn’t recognize it. Someone in the comments asked the same thing which was answered in the following, clear way:

Because it has a return statement. And it has to specify the return type at the start. In this case the type is T. T could be any type according to the code int, string, etc.

I finished the rest of the questions in the quiz and then, well, I COMPLETED THE COURSE!!! And then they emailed me this certificate:

I gotta say, I’m EXTREMELY excited! Next, I’m moving on to the first part of Harry Mattison’s Revit API course on Udemy. Since his courses are paid, I won’t be posting articles as I did here. That said, once I’ve got some apps for Revit built, even if they’re basic, I’ll definitely share.

If there’s anything else that I forgot, or needs further explaining, please let me know! Here’s a link to the previous article: Learning to Code — Part 10: Structs, Enums, Exceptions & Files.

I really appreciate you coming along with me on the first stop of this journey, and look forward to sharing more in the future!

  • Scott

Web: BIMuzer.com

Twitter: @BIMuzer

LinkedIn: Scott Rosenbloom