Learning C# Notes - Part II: Variables & Collections

After seeing classes in part 1, here are my notes on variables, which we will use to hold different data that we want to use somehow. Collections are just different ways of grouping variables.

Variable Declaration & Definition

  • Variables must be declared. This is simply “anouncing” which type the variable uses and giving it a name.

  • Optionally, we can also define a variable, that is, we give it an specific value.

int number; //We declare a variable.
string greeting = "Hello"; //We declare and define a value.

Basic Variables Types

  • Int -> Stores whole numbers (can be negative).

  • float -> Stores numbers with decimals. An “f” is written after the number.

  • double -> Same as a float but can hold twice as many decimals. A “D” is written after the number.

  • string -> Stores a chain of characters and is always surrounded by double quotes.

  • char -> Stores a single character and uses single quotes.

  • bool -> Only holds two posiible states: true and false.

int aNumber = 45;
float aFloatNumber = 0.3f;
double aDoubleNumer = 3.59D;
string aText = "Hello";
char aSingleLetter = 'J';
bool aBooleanVariable = true;
  • Remember that string variables can look like a number as any number is just a chain of characters but this doesn’t mean you can do mathematical operations with them. For this, you need to convert them to an int or float.

  • Sometimes, the variable type is implicit by context and you can just use “var” as the type.

  • We say a variable is local when is declared and used within a method, so the rest of the class has no notion of it.

  • There are a few rules when naming variables:

    • You should start with a lowcase letter.

    • You can then use letters, numbers and underscores but NO spaces.

    • Names are case sensitive.

    • A usual convention is to use camelCase.

Constants

  • You can add the keyword “const” to make any variable contant.

  • A constant hold a value that never changes, like Pi or G

  • If anything then tries to change the value of a constant an error will be produced.

const int number = 5;

Enums

  • Enums are a special type of variable. Well, they are actually a class but you can think of them as variable type.

  • They hold a group of constants that, once you define them, won’t change.

  • Enums really just hold intigers (whole numbers) but they give you the option of labeling each of them with a meaningful name.

  • So basically Enums offer more ease of use and readibility than just using numbers.

  • A classic example is that, instead of using 0, 1, 2, 3 to represent the coordinates in a compass, you use North, West, South, East.

enum Coordinates
{
  North,    // 0
  West = 1,   // 1
  South,      // 2
  East = 23,      // 23
}
  • We declare an enum starting with a capital letter (since they are really classes).

  • We then declare the elements within the curly braces, using a comma after each one.

  • See how, by default, a value of 0 is given to the first element, 1 to the second and so on.

  • We can also define our own values if we prefer.

  • If you use Fmod, an enum would correspond to a “Labeled” type paramter.

Value Types VS Reference Types

  • Something that confused me at the start is that many things that you can do with a variable, you can also do with a class. This is because both classes and variables are “types”.

  • So you can store classes in collections and pass them through methods, for example.

  • The main difference between the two, is that a variable is a “Value Type” while classes are a “Reference Type”.

  • Value types pass a copy of the value inside them while reference types pass the type instance itself.

  • If we want to pass a variable as a reference type, we can use the keyword “ref” before the variable.

  • This means that changes made to the variable by the method will affect the original that was passed in.

  • So an example below.

  • See more: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types

class DoMath 
{
    int num = 8;

    int DoSomething(int number) 
    {
      //Something is done...
    }

    DoSomething(num); // Here we are passing hte 8 value.
    DoSomething(ref num); //Here we are passing num itself.
}

Structs

  • Think about them as a custom data type. They are like a container for any number of variables. So for example, we could have a struct called Car which contains a string variable for the model, an int for the year and a bool for availability.

  • So structs are basically a variable that can contains more variables. In a way, they are like a light class as they can use variables, methods and constructors.

  • They can be useful when you want to manage data in certain ways (queues, dictionaries...) and want to refer to a few different variables in one go.

  • Struct can't have defaults on their constructors and their variables can't be initialized.

struct House
{
  public int Elevation;
  public bool Ocupied;
  public string StreetName;
  
  public CalculateDistance(int elevation) 
  {
    //We do some maths...
  }
}

Collections

  • Collections simply hold a number of variables at the same time.

  • This is useful because you can look through them and do dynamic operations like you can see below.

Arrays

  • They hold multiple variables of the same type.

  • When defining the array, you must define its size and this can’t change dynamically.

  • Is possible to create multi-dimensional arrays (arrays of arrays).

//We can declare an array by directly defining its contents:
int[] numberArray = [1, 2, 3, 4, 5];

//Or we can just specify its size:
int[] numberArray = new int[5];

//We can access any variable using its index.
//The first elements always uses 0.
numberArray[0];

//We can also check the size with:
numberArray.Lenght;

Lists

  • They function like arrays but they can be dynamically sized so you can add and substract elements during run time.

  • Lists are a generic type class and we must instantiate them so the sintax is a bit different as you can see below.

  • Lists can contain nulls.

  • Lists can do many other things: https://www.tutorialsteacher.com/csharp/csharp-list

//We declare a new list. No need to specify the size.
List<int> myNumberList = new List<int>();

//We add elements by using the Add method.
myNumberList.Add(17);

//We can remove an specific element like so.
//This woud remove the first 5 found in the list.
myNumberList.Remove(5);

//Alternatively, we can also remove using the index.
//So this would remove the third element in the list:
myNumberList.RemoveAt(3);

Dictionaries

  • Similarly to lists, they can be dynamically sized but they always contain a pair of variables which can be of any type.

  • The first type is called the Key, while the second is the Value.

  • We use a dictionary in a similar way as a List since they are also clases.

  • An important difference is that dictionaries don’t use indexes since the key value acts as the index.

  • When iterating through a dictionary with a for or foreach loop (more on this in future posts), you should not remove entries directly or you will create errors. You can store whatever you want to remove in a list, for example.

//For example, we can declare a new dictionary which will contain
//an int as the key and a string as the value.
Dictionary<int, string> numberNames = new Dictionary<int, string>();

//We add value in a similar way to a list, but we need to specify both values.
numberNames.Add(1,"One");
numberNames.Add(2,"Two");

//To remove, we only specify the key.
numberNames.Remove(2);

//Use TryGetValue() when you are not sure if a certain key 
//is in the dictionary. This will be false if there is no such key value.
numberNames.TryGetValue(2);

Queues

  • They store any number of items and these item can be of any type.

  • Queues work with a FIFO rule, so the first element to enter the queue is also the first to exit.

  • Queues are classes so they use a similar syntax as lists and dictionaries.

//We declare a queue 
Queue<int> callerIds = new Queue<int>();

//We use the Enqueue() method to add to it.
callerIds.Enqueue(1);
callerIds.Enqueue(2);
callerIds.Enqueue(3);
callerIds.Enqueue(4);

//And Dequeue() to will always remove the first element.
callerIds.Dequeue(); //This would remove the 1 value.

//We can use Peek() to see the first element without removing it.
calledIds.Peek();

Hashsets

  • This is a collection of unique elements (no repetition) that is particularly high performance.

  • Is useful to store a set of unique data so you can search it quickly.

  • You delcare them, add and remove from them is the same way as lists.