# Using 'in' C# Keyword as a Parameter Modifier

> Take advantage of C#'s 'in' keyword to modify parameters, making them immutable and passed more efficiently.

- URL: https://blog.nimblepros.com/blogs/csharp-in-parameter-keyword/
- Author: [Scott DePouw](https://blog.nimblepros.com/authors/scott/)
- Published: 2025-02-18
- Categories: [Software Development](https://blog.nimblepros.com/categories/software-development/)
- Publisher: [NimblePros](https://blog.nimblepros.com/)

---

C#, like most programming languages, has a plethora of features and functionality that would take a long time to fully encompass. I've been using C# professionally for over 15 years now and am still learning new things about the language (including features that have been around for a while). A recent example would be the subject of this very blog post: Using the `in` keyword as a parameter modifier.

The most I've done with parameter modifiers has been decorating `TryParse()`'s second parameter with the `out` keyword, to set a strongly-typed variable if the parsing succeeds.

```csharp
// Integer variable "id" initialized with the value of 5
bool parsed = int.TryParse("5", out int id);
if (parsed)
{
  _someRepository.GetById(id);
}
```

Beyond that I've not created anything with the `out` keyword, nor have I ever used other parameter modifiers such as `ref` or `in`.

After discovering some of what `in` can allow, however, I plan to fold it into my toolbox of useful features C# has to offer. Let's explore what it does, how you can use it, and when one should probably avoid using it!

## A Primer on Using the `in` Parameter Modifier

To use the `in` parameter modifier, simply decorate any parameters with the keyword in your method declaration:

```csharp
public interface ILogger
{
  // Interface and implementation must match all parameter modifiers.
  public void LogMessage(in string message);
}

public class ConsoleLogger : ILogger
{
  public void LogMessage(in string message) => Console.WriteLine(message);
}
```

You don't have to explicitly declare your passed arguments as `in`, but you can if you want:

```csharp
public class Example
{
  private readonly ILogger _logger = new ConsoleLogger();
  
  public void DoStuff()
  {
    string myMessage = "Hello, World!";
    _logger.LogMessage(myMessage);
    _logger.LogMessage(in myMessage);
    _logger.LogMessage("Some Inline String");
    
    // Compiler error: "An expression cannot be used in this context
    // because it may not be passed or returned by reference"
    // _logger.LogMessage(in "Some Inline String");
  }
}
```

There is an occasion where you must supply the `in` keyword, however: When you overload your method to have a version with `in` and a version without it:

```csharp
public interface ILogger
{
  public void LogMessage(in string message);
  public void LogMessage(string message);
}

public class Example
{
  private readonly ILogger _logger = new ConsoleLogger();
  
  public void DoStuff()
  {
    string myMessage = "Hello, World!";
    // Calls version with "in"
    _logger.LogMessage(in myMessage);
    // Inline strings won't be able to call the version with "in"
    // _logger.LogMessage(in "Some Inline String");
    
    // Calls version without "in"
    _logger.LogMessage(myMessage);
    _logger.LogMessage("Some Inline String");
  }
}

```

Off the top of my head I can't think of a reason to overload methods in this manner (but I'm sure there are use cases). But if you ever need to, the capability exists!

Now that we know the syntax, let's dive into why we'd want to use the `in` parameter modifying keyword.

## Pass By Readonly Reference

When a method modifies a parameter with the `in` keyword, the variable is passed in by readonly reference. Normally, value types (such as `int`) have their value copied over to the parameter ("pass by value"), and reference types (such as `string`) are passed by not-readonly reference. Using the `in` modifier changes the behavior.

- Value types are now passed by reference (and are readonly), instead of "pass by value"
- Reference types are now passed by **readonly** reference

The "readonly" aspect is the game-changer when using `in`. When using this modifier, attempting to change the input parameter in any way results in a compiler error!

```csharp
public void LogMessage(in string message)
{
  // Compiler error: "Cannot assign to variable 'message' or use it as the
  // right hand side of a ref assignment because it is a readonly variable"
  message = "Changing!";
}
```

For primitive value types, this doesn't add much. Since value types are copied, it doesn't matter what you do with the copied value within the method. The calling code will never know or care that the copied value was modified. We'll get to a use case for using `in` on value types later, but one takeaway here is that you don't really ever need to use `in` on primitive value types (such as `int`), since there's no real benefit to it.

Reference types, though? That's another story! How many times have you worked in an application that had some method passing in a `string` or some other reference type, only for the method to unintentionally modify the parameter by side effect? I know I've run into it on several occasions. Wouldn't it be nice to guarantee that when you call a method, you know that it cannot modify your reference types?

This is what `in` lets you do!

> NOTE: The `string` class is already immutable, so using the `in` keyword, while granting some extra compile-time checks to assure the parameter isn't assigned to in the method itself, doesn't impact the behavior. The outer `string` variables will remain untouched. However, this does demonstrate the compile-time safety added when using the `in` keyword!

```csharp
public void LogMessage(in string message) => Console.WriteLine(message);

// When using the above method, we know that our precious string cannot be changed!
string myPreciousString = GetPreciousString();
_logger.LogMessage(myPreciousString);

// Safely rely on the fact that myPreciousString is not changed.
```

## We Can Fix Primary Constructors Now, Right?

You now have the power to declare parameters immutable. Perfect! One of my biggest gripes about [C# 12's new Primary Constructors feature](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/primary-constructors) is that the primary constructor values **are not readonly**. Lame! This means that this class

```csharp
public class SomeClass
{ 
  // _logger cannot be modified after construction
  private readonly ILogger _logger;
  
  public SomeClass(ILogger logger) => _logger = logger;
}
```

is not the same as this class (despite what IDEs may lead you to believe by suggesting this as a "code fix"):

```csharp
public class SomeClass(ILogger logger)
{
  // I can freely modify "logger" any time I want!
}
```

But we can solve that problem now, right? Just use our shiny new toy, `in`! ...Right?


```csharp
public class SomeClass(in ILogger logger)
{
  // Unfortunately, this doesn't work!
}
```

While you *can* declare your class with a primary constructor like this, you cannot then *use* the `in`-decorated parameter. Attempting to do so results in a compiler error:

```csharp
public class SomeClass(in ILogger logger)
{
  public void DoStuff()
  {
    // Error: "Cannot use ref, out, or in primary constructor
    // parameter 'logger' inside an instance member"
    logger.LogMessage("Foo");
  }
}
```

There does appear to be some buzz within Microsoft about allowing users to declare these primary constructor parameters readonly in the future. Unfortunately, we cannot use `in` to solve this big issue with primary constructors presently.

But enough about what we can't do. Let's take a look at a use case for the `in` modifier for value types: Efficiency!

## Passing Large Value Objects By Reference

Earlier I noted that it's not too useful to pass primitive value types (such as `int`) using `in`: There's no benefit to your code, and it adds complexity for no real gain.

However, what if you have a value object that has a large footprint? A `struct`, after all, is passed by value. What if you have code that is called rapidly, or otherwise must be super performant? It'd be convenient if we had a way to not copy around large value instances, while still maintaining the benefit of "pass by value" immutability.

`in` lets us do just that!

```csharp
public readonly struct SomeStruct
{
  public int Id { get; init; }
  // Imagine a lot more things in here.
}

public interface ISomeProcess
{
  void Process(in SomeStruct structToProcess);
}

public class Example(ISomeProcess someProcess)
{
  public void DoSomethingEfficiently(in SomeStruct myStruct)
  {
    // struct is passed by readonly reference, preventing
    // us from making expensive copies in memory.
    someProcess.Process(myStruct);
  }
}
```

The struct is passed to `Process()` by readonly reference. The implementation of `Process()` cannot modify the given struct, but it also didn't have to copy the entire struct in order to accomplish this. Using `in` is saving us a lot of memory usage!

> NOTE: The struct in this example is a `readonly` struct. Using a non-`readonly` struct may actually negatively impact performance when using the `in` keyword. See [this article](https://devblogs.microsoft.com/premier-developer/the-in-modifier-and-the-readonly-structs-in-c/) for more information.

## Summary

- The `in` parameter modifier keyword allows us to change how method parameters are passed. Value types and reference types alike both change from "pass by value" and "pass by reference", respectively, into "pass by readonly reference."
- Use the `in` parameter modifier when you want to guarantee that a reference type will not be modified by the method being called.
- Use the `in` parameter modifier when you have large value types that would be expensive to copy in memory, to improve efficiency.
- Do not use the `in` parameter on primitive value types (such as `int`).
- We cannot use the `in` parameter to fix the "not readonly" issue present with primary constructors.

## References

- [Method parameters and modifiers - `in` parameter modifier - Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/method-parameters#in-parameter-modifier)
- [Software Engineering Stack Exchange Answer - Sebastian Redl](https://softwareengineering.stackexchange.com/a/402534)
- [The ‘in’-modifier and the readonly structs in C# - Sergey Tepliakov](https://devblogs.microsoft.com/premier-developer/the-in-modifier-and-the-readonly-structs-in-c/)
- Special thanks to [GitHub user Arkane5](https://github.com/Arkane5) for correcting a couple mistakes I made when authoring this post!
