0Pricing
C# Academy · Leçon

Immuabilité avec init et with

Utilisez des accesseurs init uniquement pour créer des objets immuables et des expressions with pour produire des copies modifiées de manière non destructive.

Immuabilité avec init et with est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.

Qu’est-ce que l’immuabilité

Un objet immuable ne peut pas être modifié après sa création. L’immuabilité empêche les modifications accidentelles, rend les objets sûrs par défaut dans un environnement multithread et simplifie le raisonnement sur le code. C# fournit des accesseurs init et des expressions with pour rendre l’immuabilité facile à utiliser.

Accesseurs définis uniquement lors de l’initialisation

Un accesseur init permet de définir une propriété pendant l’initialisation de l’objet (dans le constructeur ou l’initialiseur d’objet), mais jamais par la suite. C’est l’équivalent immuable de set.

public class Point
{
    public double X { get; init; }
    public double Y { get; init; }
}

var p = new Point { X = 3.0, Y = 4.0 }; // OK — init phase
p.X = 5.0; // COMPILE ERROR — cannot set after init

// All of these are valid init-phase assignments:
var p2 = new Point(X: 1.0, Y: 2.0);
var p3 = new Point { X = 0, Y = 0 };

init dans les propriétés positionnelles des enregistrements

Par défaut, les propriétés positionnelles des enregistrements sont définissables uniquement avec init : c’est ce qui rend les enregistrements immuables. Le compilateur génère get; init; pour chaque paramètre positionnel.

// This record:
public record Person(string Name, int Age);

// Is equivalent to:
public record Person
{
    public string Name { get; init; }
    public int Age    { get; init; }
    public Person(string Name, int Age) { this.Name = Name; this.Age = Age; }
    // + Deconstruct, Equals, GetHashCode, ToString
}

var alice = new Person("Alice", 30);
alice.Name = "Bob"; // COMPILE ERROR

Expressions with : mutation non destructive

Une expression with crée une copie d’un enregistrement en modifiant certaines propriétés. L’original reste inchangé : c’est la véritable immuabilité.

public record Person(string Name, int Age, string Email);

var alice = new Person("Alice", 30, "alice@example.com");

// Create a modified copy — alice is unchanged
var olderAlice = alice with { Age = 31 };
var renamed    = alice with { Name = "Alicia", Email = "alicia@example.com" };

Console.WriteLine(alice.Name);      // Alice (unchanged)
Console.WriteLine(olderAlice.Age);  // 31
Console.WriteLine(renamed.Name);    // Alicia

with sur les types qui ne sont pas des enregistrements

C# 10 autorise with sur toute structure ou classe qui possède la sémantique d’un constructeur de copie, mais cette construction est plus naturelle avec les enregistrements. Pour les classes, vous devez l’implémenter manuellement.

// struct with with-expression:
public struct Temperature
{
    public double Celsius { get; init; }
    public double Fahrenheit => Celsius * 9 / 5 + 32;
}

var t1 = new Temperature { Celsius = 20 };
var t2 = t1 with { Celsius = 25 }; // copy with change
Console.WriteLine(t1.Celsius); // 20 — unchanged
Console.WriteLine(t2.Celsius); // 25

Chaînage d’expressions with

Chaînez plusieurs expressions with pour construire des transformations complexes, chaque étape créant une nouvelle valeur immuable à partir de la précédente.

public record Order(int Id, string Status, decimal Total, DateTime UpdatedAt);

var order = new Order(42, "Pending", 99.99m, DateTime.UtcNow);

// Apply a promotion discount then mark as confirmed
var finalOrder = order
    with { Total    = order.Total * 0.9m }    // 10% off
    with { Status   = "Confirmed" }
    with { UpdatedAt = DateTime.UtcNow };

Console.WriteLine(order.Status);     // Pending (original unchanged)
Console.WriteLine(finalOrder.Status); // Confirmed

Propriétés calculées sur les types immuables

Les propriétés dérivées des types immuables sont naturellement pures : elles sont calculées à partir des valeurs de propriétés fixes et renvoient toujours le même résultat pour une même entrée.

public record Money(decimal Amount, string Currency)
{
    public Money Add(Money other)
    {
        if (Currency != other.Currency)
            throw new InvalidOperationException("Currency mismatch");
        return this with { Amount = Amount + other.Amount };
    }

    public Money Multiply(decimal factor) =>
        this with { Amount = Amount * factor };

    public override string ToString() =>
        $"{Amount:F2} {Currency}";
}

var price = new Money(10.00m, "USD");
var tax   = price.Multiply(0.08m);
var total = price.Add(tax);
Console.WriteLine(total); // 10.80 USD

Collections immuables

Combinez les enregistrements avec ImmutableList<T> et d’autres types de System.Collections.Immutable pour obtenir des structures de données entièrement immuables.

using System.Collections.Immutable;

public record ShoppingCart(
    string UserId,
    ImmutableList<CartItem> Items)
{
    public ShoppingCart AddItem(CartItem item) =>
        this with { Items = Items.Add(item) };

    public ShoppingCart RemoveItem(int productId) =>
        this with { Items = Items.RemoveAll(i => i.ProductId == productId) };

    public decimal Total => Items.Sum(i => i.Price * i.Quantity);
}

Sécurité des threads grâce à l’immuabilité

Les objets immuables sont intrinsèquement sûrs vis-à-vis des threads : aucune synchronisation n’est nécessaire lorsque vous les partagez entre plusieurs threads, car leur état ne peut plus changer après leur construction.

// Immutable config record shared across all threads safely
public record AppConfig(
    string ConnectionString,
    int MaxRetries,
    TimeSpan Timeout);

// Register as singleton — safe because record is immutable
builder.Services.AddSingleton(
    new AppConfig(
        ConnectionString: config["DB"]!,
        MaxRetries: 3,
        Timeout: TimeSpan.FromSeconds(30)));

// Any thread can read this simultaneously without locks

Cas réel : reconstitution fonctionnelle à partir d’événements

Les enregistrements immuables s’associent naturellement à la reconstitution à partir d’événements : chaque événement du domaine est immuable et l’état est dérivé par accumulation des événements, sans mutation ni surprise.

public record OrderState(
    int Id,
    string Status = "Draft",
    decimal Total = 0m);

public static OrderState Apply(OrderState state, object evt) => evt switch
{
    OrderPlaced   e => state with { Status = "Pending", Total = e.Total },
    OrderShipped  _ => state with { Status = "Shipped" },
    OrderCancelled _ => state with { Status = "Cancelled" },
    _ => state
};

// Fold events to get current state:
var state = events.Aggregate(
    new OrderState(id),
    Apply);

Vérification rapide

Que fait une expression « with » à l’enregistrement d’origine ?

Récapitulatif : immuabilité avec l’initialisation et with

À retenir :

  • Accesseur init : définissable uniquement pendant l’initialisation, jamais après
  • Par défaut, les propriétés positionnelles des enregistrements sont définissables uniquement avec init
  • Expression with : crée une copie modifiée, sans changer l’original
  • Chaînez les expressions with pour effectuer des transformations en plusieurs étapes
  • Les types immuables sont sûrs vis-à-vis des threads sans synchronisation
  • Combinez-les avec ImmutableList<T> pour obtenir des graphes d’objets entièrement immuables

Questions Fréquemment Posées

La leçon « Immuabilité avec init et with » est-elle gratuite ?

Oui — le texte complet de « Immuabilité avec init et with » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Immuabilité avec init et with » ?

Utilisez des accesseurs init uniquement pour créer des objets immuables et des expressions with pour produire des copies modifiées de manière non destructive. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer C# Academy ?

Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Immuabilité avec init et with » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?

Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Types record : notions de base et syntaxe
  2. Immuabilité avec init et with
  3. Égalité des valeurs et déconstruction
  4. Records dans la conception pilotée par le domaine
← Retour à C# Academy