Why does the "in" keyword allow mutation of properties C#?

204 Views Asked by At

I am currently working on a function where an object (of self written type Catalog) is passed and shall not be mutated / changed in the called function. Here a quick example.


public override bool Migrate(in Catalog fromCatalog)
{
    fromCatalog.SupplierId = 1; //works, but why
}

I want to strictly undermine this behaviour and disallow mutating any properties of the passed object.

2

There are 2 best solutions below

4
On BEST ANSWER

Because the in modifier applies only to the variable (the parameter in this case). It prevents the parameter from having its value changed to refer to a different object.

public bool Migrate(in Catalog fromCatalog)
{
/* Error CS8331  Cannot assign to variable 'fromCatalog' 
or use it as the right hand side of a ref assignment 
because it is a readonly variable */
    fromCatalog = new Catalog(); 

    fromCatalog.SupplierId = 1;
}

and create a shallow copy of the object so that you don't change anything in the object you passed (within the class)

example:

public Catalog CreateACopy()
{
    Catalog obj = (Catalog)this.MemberwiseClone();
    // and other...
    return obj;
}
        

utilization:

public class Program 
{
    private static void Main()
    {
        Catalog catalog = new Catalog();
        new Program().Migrate(catalog.CreateACopy());
    }
    public bool Migrate(in Catalog fromCatalog)
    {
        fromCatalog.SupplierId = 1;
    }
}
0
On

It works because the Catalog has a writeable property. C# does not have a concept of constant values the same way for example C++ does. So fromCatalog is just another value you can pass around, call methods on, set properties, etc.

But that does not mean it makes much sense to write code like this. The in keyword is mostly useful to avoid copies of a value type. But if the value type is mutable the compiler has to create a defensive copy anyway, just to prevent the original object from being modified.

So the general recommendation is to make your value types immutable/readonly, this avoids the issue. See also why mutable structs are evil.