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 in parameter modifier in C# specifies that an argument is passed by reference, but its value cannot be modified by the called method. It enforces read-only semantics on the referenced variable, allowing the compiler to pass a pointer to the memory location rather than copying the payload, while strictly guaranteeing immutability within the method scope.
// Method declaration using the 'in' modifier
public void ProcessData(in int data)
{
    // data = 5; // Compiler Error CS8331: Cannot assign to variable 'data' because it is a readonly variable
}

// Method invocation
int number = 10;

// The 'in' modifier at the call site is optional
ProcessData(in number); // Explicit invocation
ProcessData(number);    // Implicit invocation

Core Mechanics

  • Pass-by-Reference: Under the hood, the CLR passes a managed pointer (ref) to the argument.
  • Read-Only Enforcement: The compiler treats the parameter as a readonly variable. You cannot reassign the parameter, nor can you modify any of its fields or properties (if it is a value type).
  • Temporary Variables: Unlike ref and out, in parameters accept constants, literals, and expressions. If an expression or a type requiring an implicit conversion is passed, the compiler automatically generates a hidden temporary local variable, evaluates the expression into it, and passes a reference to that temporary variable.
public void Calculate(in double value) { }

// Passing a literal. The compiler creates a temporary variable.
Calculate(42.5); 

// Passing an expression. The compiler creates a temporary variable.
int x = 5;
Calculate(x + 10); 

Call Site Syntax and Overload Resolution

The in keyword is optional at the call site, but its presence or absence dictates compiler behavior regarding type matching and overload resolution:
  1. Explicit in at call site: Forces the compiler to pass the argument by reference. The argument’s type must exactly match the parameter’s type. No implicit conversions or temporary variables are permitted.
  2. Implicit (omitted) in at call site: Allows the compiler to create a temporary variable if there is an implicit conversion available from the argument type to the parameter type.
public void Print(in double value) { }

double d = 5.5;
int i = 10;

Print(in d); // Valid: Exact type match.
Print(d);    // Valid: Exact type match.
Print(i);    // Valid: Implicit conversion from int to double creates a temporary variable.

// Print(in i); // Compiler Error: Argument 1: cannot convert from 'in int' to 'in double'.
You can overload methods based on pass-by-value versus in. However, you cannot overload methods if the only difference in their signatures is between in, ref, and out.
// Valid overloading
public void Execute(int x) { }
public void Execute(in int x) { }

// Invalid overloading (Compiler Error CS0663)
public void Process(ref int x) { }
public void Process(in int x) { } 

Defensive Copies

When an in parameter is a struct that is not explicitly marked with the readonly modifier, the compiler cannot guarantee that calling a method or accessing a property on that struct will not mutate its internal state. To uphold the immutability guarantee of the in modifier, the compiler will silently create a “defensive copy” of the struct on the stack before invoking any of its instance members. The member is then invoked on the copy rather than the original reference. If the struct is declared as a readonly struct, the compiler bypasses this step, as the type itself guarantees immutability.
Master C# with Deep Grasping Methodology!Learn More