Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The with expression in C# performs non-destructive mutation by producing a new object instance that is a shallow copy of an existing object, with specified properties or fields modified. While frequently used with immutable data models, the with expression does not enforce immutability; it merely leaves the original object’s state unaltered during the copy operation. If the original object contains standard set properties or mutable fields, the new instance remains fully mutable.
using System;

public record Point(int X, int Y);

public class Program
{
    public static void Main()
    {
        Point originalInstance = new Point(10, 20);
        
        // Create a shallow copy with the X property modified
        Point newInstance = originalInstance with { X = 50 };

        Console.WriteLine(originalInstance); // Output: Point { X = 10, Y = 20 }
        Console.WriteLine(newInstance);      // Output: Point { X = 50, Y = 20 }
    }
}

Supported Types

The with operator is natively supported by the following type declarations:
  • record class (reference types)
  • record struct (value types)
  • struct (all value types)
  • Anonymous types

Technical Mechanics

Compiler Implementation When the with expression is evaluated, the compiler’s behavior depends strictly on the underlying type:
  • For record class: The compiler invokes a hidden, synthesized virtual method named <Clone>$. This method calls a copy constructor (e.g., protected MyRecord(MyRecord original)) that duplicates the state of the original record. Developers can customize the shallow copy behavior by manually defining this copy constructor.
  • For struct and record struct: No <Clone>$ method or copy constructor is generated. Instead, the compiler emits a standard struct assignment (a member-wise copy) to a temporary variable, mutates the specified properties and fields on that temporary variable, and then yields the resulting value.
  • For Anonymous Types: The compiler generates a new instance of the anonymous type, copying the unspecified fields from the original instance and applying the new values from the initializer.
Initialization and init Accessors The property assignments defined within the with block are executed during the object’s initialization phase. This allows the with expression to assign values to properties defined with init-only setters, bypassing the restriction that typically prevents modification after constructor execution. Shallow Copy Semantics The with operator performs a strictly shallow copy.
  • Value Types: Nested value types are copied by value.
  • Reference Types: Nested reference types are copied by reference. The newly created object will hold pointers to the exact same memory addresses for any nested objects, collections, or arrays as the original instance.

Syntax Rules and Constraints

  • Empty Initializer: The initializer block can be empty (originalInstance with { }). This produces an exact shallow copy of the original object with no modifications.
  • Member Accessibility and Mutability: You can only modify members that are accessible (e.g., public or internal). Properties must have an accessible set or init accessor. Fields must be mutable (i.e., not declared as readonly or const).
  • Type Preservation: The compile-time type of a with expression is identical to the compile-time type of the operand. Polymorphic cloning is supported for record class types; because the synthesized <Clone>$ method is virtual, if the runtime type derives from the compile-time type, the clone will correctly maintain the derived runtime type.
Master C# with Deep Grasping Methodology!Learn More