Nueva sintaxis en C# 12 con .NET 8

C# 12 es la nueva versión de C# disponible en .NET 8. Dado que .NET y C# son compatibles con versiones anteriores, podemos combinar la nueva sintaxis con otras características incluidas en C# 11, C# 10 y anteriores.

Si deseas puedes ver este video donde se explica igualmente cada mejora:

Revisemos cada característica en C# 12 con un ejemplo:

InLine Array

Esta es una nueva forma de crear matrices en C# usando el atributo [System.Runtime.CompilerServices.InlineArray], donde necesitamos especificar el tamaño (cuántas posiciones necesitamos en la matriz) y agregar una propiedad con el tipo primitivo (int, double, string, etc…) donde se guardará el valor. Pero por defecto, cada posición tendrá el valor predeterminado definido para el tipo primitivo; por ejemplo, para el tipo int, será 0.

// InLine Arrays

var array = new MyArray();

array[0] = 2;

foreach (var item in array)
{
    Console.WriteLine(item);
}

[System.Runtime.CompilerServices.InlineArray(5)]
public struct MyArray
{
    private int _element;
}

Parámetros predeterminados en funciones lambda

Ahora podemos definir un parámetro opcional en las funciones lambda, estableciendo un valor predeterminado para el parámetro. En el siguiente ejemplo, establecemos 1 como valor predeterminado para la función IncrementBy. La función aumentará +1 cuando no establezcamos un valor para este parámetro.

//default parameters in lambda functions
var IncrementBy = (int source, int increment = 1) => source + increment;

Console.WriteLine(IncrementBy(5)); // 6
Console.WriteLine(IncrementBy(5, 2)); // 7

Parámetro Params en funciones lambda

Usando parámetros, podemos recibir dinámicamente parámetros con el mismo tipo en nuestras funciones o métodos; Ahora también se admite para funciones de Lambda:

// Params parameter in lamba functions
var sum = (params int[] values) =>
{
    int sum = 0;
    foreach (var value in values)
        sum += value;

    return sum;
};

Console.WriteLine(sum(1, 2, 1, 1, 1, 1)); // 7
Console.WriteLine(sum(1, 1)); // 2

Constructor principal

En clases simples, ahora es posible declarar el constructor con facilidad. Esta es una característica incluida para los records, y ahora también está disponible para las clases.

Antes de C# 12

public class Person
{
    public string Name { get; set; }
    public string LastName { get; set; }

    public void Person(string name, string lastname)
    {
      Name = name;
      LastName = lastname;
    }
}

Después de C# 12

// primary constructor
Person newPerson = new Person("Miguel", "Teheran");

public class Person(string name, string lastname)
{
    public string Name { get; set; } = name;
    public string LastName { get; set; } = lastname;
}

Alias de cualquier tipo

Usando la función “alias any type”, podemos crear un alias para un valor primitivo para mejorar la legibilidad o para una clase con un nombre largo para hacer el código más corto.

En el siguiente ejemplo, podemos usar el alias City para aclarar lo que estamos guardando en la colección, que es una Lista de strings.

// Alias any type
using City = string;

List<string> CityList = new List<City>();

CityList.Add("New York");
CityList.Add("Bogotá");
CityList.Add("Lima");

foreach (City city in CityList)
{
    Console.WriteLine(city);
}

Interceptores

Con esta nueva característica, podemos interceptar cualquier línea de código en tiempo de ejecución y cambiar la lógica para personalizar los comportamientos esperados. Esto es útil en caso de que necesitemos admitir un escenario específico para un sistema operativo y evitar excepciones. Pero también, esto podría ser confuso y puede traer desafíos para identificar problemas o comportamientos inesperados en entornos de producción.

Primero, necesitamos habilitar esta opción agregando esta línea a nuestro archivo de proyecto:

<Features>InterceptorsPreview</Features>

Luego necesitamos crear un nuevo atributo InterceptsLocationAttribute.cs,

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public sealed class InterceptsLocationAttribute(string filePath, int line, int character) : Attribute
    {

    }
}

Este es el siguiente ejemplo del código; tenemos una clase HelloWorld con un método HelloWorld que simplemente imprime en el terminal HelloWorld.

// interceptors

static class Program
{
    public static void Main()
    {
        HelloWord helloWord = new HelloWord();
        helloWord.HelloWorld();
        Console.ReadLine();
    }
}

class HelloWord
{
    public void HelloWorld() => Console.WriteLine("Hello World");
}

La idea ahora es crear un interceptor para cambiar la línea 8, que llamamos el método HelloWorld en la clase de programa. Para conseguirlo, debemos crear un interceptor de la siguiente manera:

using System.Runtime.CompilerServices;

namespace ConsoleApp1
{
    static class Interceptor
    {
        [InterceptsLocation("C:\\Personal\\demonet8\\ConsoleApp1\\Program.cs", line: 15, character: 17)]
        public static void InterceptorMethod(this HelloWord c)
        {
            c.HelloWorld();
            Console.WriteLine("Hi!");
        }
    }
}

Mejoremos la funcionalidad de visualización incluyendo la ruta del archivo, el número de línea y la posición del carácter. En lugar del ordinario “Hello, World”, ahora mostraremos un “¡Hi!” debido al interceptor.

Referencia: https://www.c-sharpcorner.com/article/what-is-new-in-c-sharp-12/

Recuerda siempre seguir aprendiendo con mis cursos en mteheran.dev/cursos