in parameter modifier (C# Reference)

The in keyword causes arguments to be passed by reference. It is like the ref or out keywords, except that in arguments cannot be modified by the called method. Whereas ref arguments may be modified, out arguments must be modified by the caller, and those modifications are observable in the calling context.

int readonlyArgument = 44;
InArgExample(readonlyArgument);
Console.WriteLine(readonlyArgument);     // value is still 44

void InArgExample(in int number)
{
    // Uncomment the following line to see error CS8331
    //number = 19;
}

The preceding example demonstrates that the in modifier is usually unnecessary at the call site. It is only required in the method declaration.

Note

The in keyword can also be used with a generic type parameter to specify that the type parameter is contravariant, as part of a foreach statement, or as part of a join clause in a LINQ query. For more information on the use of the in keyword in these contexts, see in, which provides links to all those uses.

Variables passed as in arguments must be initialized before being passed in a method call. However, the called method may not assign a value or modify the argument.

Although the in, ref, and out keywords cause different run-time behavior, they are not considered part of the method signature at compile time. Therefore, methods cannot be overloaded if the only difference is that one method takes a ref or in argument and the other takes an out argument. The following code, for example, will not compile:

class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded 
    // methods that differ only on in, ref and out".
    public void SampleMethod(in int i) { }
    public void SampleMethod(ref int i) { }
}

Overloading based on the presence of in is allowed:

class InOverloads
{
    public void SampleMethod(in int i) { }
    public void SampleMethod(int i) { }
}

Overload resolution rules

You can understand the overload resolution rules for methods with by value vs. in arguments by understanding the motivation for in arguments. Defining methods using in parameters is a potential performance optimization. Some struct type arguments may be large in size, and when methods are called in tight loops or critical code paths, the cost of copying those structures is critical. Methods declare in parameters to specify that arguments may be passed by reference safely because the called method does not modify the state of that argument. Passing those arguments by reference avoids the (potentially) expensive copy.

Specifying in for arguments at the call site is typically optional. There is no semantic difference between passing arguments by value and passing them by reference using the in modifier. The in modifier at the call site is optional because you don't need to indicate that the argument's value might be changed. You explicitly add the in modifier at the call site to ensure the argument is passed by reference, not by value. Explicitly using in has the following two effects:

First, specifying in at the call site forces the compiler to select a method defined with a matching in parameter. Otherwise, when two methods differ only in the presence of in, the by value overload is a better match.

Second, specifying in declares your intent to pass an argument by reference. The argument used with in must represent a location that can be directly referred to. The same general rules for out and ref arguments apply: You cannot use constants, ordinary properties, or other expressions that produce values. Otherwise, omitting in at the call site informs the compiler that you will allow it to create a temporary variable to pass by read-only reference to the method. The compiler creates a temporary variable to overcome several restrictions with in arguments:

  • A temporary variable allows compile-time constants as in parameters.
  • A temporary variable allows properties, or other expressions for in parameters.
  • A temporary variable allows arguments where there is an implicit conversion from the argument type to the parameter type.

In all the preceding instances, the compiler creates a temporary variable that stores the value of the constant, property, or other expression.

The following code illustrates these rules:

static void Method(in int argument)
{
    // implementation removed
}

Method(5); // OK, temporary variable created.
Method(5L); // CS1503: no implicit conversion from long to int
short s = 0;
Method(s); // OK, temporary int created with the value 0
Method(in s); // CS1503: cannot convert from in short to in int
int i = 42;
Method(i); // passed by readonly reference
Method(in i); // passed by readonly reference, explicitly using `in`

Now, suppose another method using by value arguments was available. The results change as shown in the following code:

static void Method(int argument)
{
    // implementation removed
}

static void Method(in int argument)
{
    // implementation removed
}

Method(5); // Calls overload passed by value
Method(5L); // CS1503: no implicit conversion from long to int
short s = 0;
Method(s); // Calls overload passed by value.
Method(in s); // CS1503: cannot convert from in short to in int
int i = 42;
Method(i); // Calls overload passed by value
Method(in i); // passed by readonly reference, explicitly using `in`

The only method call where the argument is passed by reference is the final one.

Note

The preceding code uses int as the argument type for simplicity. Because int is no larger than a reference in most modern machines, there is no benefit to passing a single int as a readonly reference.

Limitations on in parameters

You can't use the in, ref, and out keywords for the following kinds of methods:

  • Async methods, which you define by using the async modifier.
  • Iterator methods, which include a yield return or yield break statement.

C# Language Specification

For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.

See Also

C# Reference
C# Programming Guide
C# Keywords
Method Parameters Reference Semantics with Value Types