C#

Record types

Record types are a new type of class in C# that are meant to make it easier to create immutable reference types. They are immutable by default and are designed to be used as data containers.

Defining a record type

There are 2 ways to define a record type:

  1. Positional parameters

    This component was made by Stratis Dermanoutsos. The code can be found here.
  2. Standard property syntax

    This component was made by Stratis Dermanoutsos. The code can be found here.

Comparing records

One of the main benefits of a record is the fact that, as it’s built for data, it is a very efficient way to compare two objects.

This component was made by Stratis Dermanoutsos. The code can be found here.

The above example outputs True as the values of the two objects’ attributes are equal.

On the other hand, if we use class, the result will be False as the two objects are not the same.

This component was made by Stratis Dermanoutsos. The code can be found here.

In general,

  • For class types, two objects are equal if they refer to the same object in memory.
  • For record types, two objects are equal if they are of the same type and store the same values.

Extension methods

Extension methods are defined as static methods but are called by using instance method syntax. Their first parameter specifies which type the method operates on.

They’re basically a way to extend a class’ functionality.

  • Why is this useful when you can just inherit a class?

    Because you can’t always do that or you may not want to do that.

For example, let’s say we want to add a NotEquals method for the String data type. Now, String is a sealed class which means that it cannot be inherited so we need to use an Extensions Method to add any functionality to it.

This component was made by Stratis Dermanoutsos. The code can be found here.

To call this method now, there are 2 simple ways.

This component was made by Stratis Dermanoutsos. The code can be found here.

Null-Coalescing Operator

The ?? operator will return the value of its left-hand operand if it is not null. Else, it returns the right one.

This component was made by Stratis Dermanoutsos. The code can be found here.
This component was made by Stratis Dermanoutsos. The code can be found here.

This operator can also be used in assignments. By using ??= to assign a value, the compiler first checks if the variable you’re trying to assign is null first. Only if it is will the value be assigned to it.

This component was made by Stratis Dermanoutsos. The code can be found here.

So, 1 was not assigned to x as it was not null. It already had a value equal to 32.

Generics

Generics in C# allow for the creation of classes and methods that can work with multiple types of data, rather than being limited to a specific data type. When a class or method is defined as generic, placeholders (also known as type parameters) are used to represent the types of data that the class or method will work with.

This allows for flexibility and reusability in your code, as the same class or method can be used with different data types without the need for multiple copies of the code.

Generic classes

For an example of generics in a class, you can think of the List data structure. In C#, this data structure is made to work will all objects, no matter what their type is.

To achieve that, it is defined as follows:

This component was made by Stratis Dermanoutsos. The code can be found here.

To instantiate a list of integers, for example, you will replace the T placeholder with the int data type.

This component was made by Stratis Dermanoutsos. The code can be found here.

Generic methods

There are several things worth mentioning about Generic methods in C#:

  1. Generic methods allow you to define a method that can work with different types of data. You can specify the data type when you call the method.

    For example, consider the following method.

    This component was made by Stratis Dermanoutsos. The code can be found here.

    When you call it, the output of the program heavily relies on the type of the parameter provided.

    This component was made by Stratis Dermanoutsos. The code can be found here.
  2. You can define a generic method using the <T> syntax, where T is a type parameter that represents the type of data you want to work with.

    Modifying the above method, we get:

    This component was made by Stratis Dermanoutsos. The code can be found here.

    Now, with the same input, we get similar but not the same results.

    This component was made by Stratis Dermanoutsos. The code can be found here.

    The call using a Boolean parameter will not compile as this type does not inherit from the IComparable interface.

  3. When calling a generic method, you can either specify the type parameter explicitly (e.g. MyMethod<int>(5)) or let the compiler infer the type parameter based on the arguments you pass to the method (e.g. MyMethod(5)).

    As you’ve noticed by now in the above examples, we explicitly specify the type of each parameter.

    However, if we just used the following, we’d get the exact same results as the compiler is smart enough to get the type itself from the parameter provided.

    This component was made by Stratis Dermanoutsos. The code can be found here.
  4. Generic methods can be used to create extension methods that work with any type that meets certain criteria, such as implementing a specific interface.

    This component was made by Stratis Dermanoutsos. The code can be found here.

    Now, we can use this method to compare any value1 that implements the interface IComparable to any value2 of the same type.

    This component was made by Stratis Dermanoutsos. The code can be found here.

Resources