Their functioning has already been described in What are the out and ref parameters (the example of ref
is artificial and not very good, is the same of the question here) and What good is this 'in' in C#? and even a little in What are pointers?, so I won’t go into too much detail.
The first, causes only the value to be passed to the argument
This is incorrect, the in
only promises that it will receive an object by reference and that it will not modify it.
The examples with in
should not use any of this, there are no copy gains because the pointer size is even larger than the whole dice. If you don’t have a large object don’t use the in
.
The third example is no longer necessary as demonstrated by the question itself and in fact neither tuple should be used (the example is very bad, until the use of tuple is wrong there).
The last example is a classic case of method that does too many things and should be unlocked in several.
The use of the three always occurs with objects that we don’t want to copy directly for some reason.
The main reason is that this object is too big to be copied (in general more than 16 bytes) what would cost expensive for it exists mainly the in
since the idea is to have an object in the stack (one struct
and even more a ref struct
that has more chance of being a large object) and wants to pass it to the called method without copying the object that is large. C# has recently given preference for allocating object to stack to reduce the pressure on Garbage Collector which makes the code slower and paused and so has abused some large objects in the stack what did not happen in the past. Do not worry about the in
if you are not adopting the preferred allocation pattern in the stack, it is for more advanced programming that requires mastering various knowledge to do right (not that anyone can not use, but if not understand all commitments will make wrong use, why I say that can not choose what to learn, or learn everything or stay always on the surface).
The ref
can be used for this but it does not give guarantees on its modification what often the guarantee is desired, and with this guarantee the compiler can do some optimizations. In part you can think of him as a in
that allows you to change its value normally. In part it serves for another that I will quote below.
But the ref
can also be used to effectively allow a change that would normally not be allowed. For example, if you pass a string as an argument for a method, it is a reference, and how string is immutable if you want to change something just by creating another string, But if you create another one, how are you going to tell the one you called that now she must have another object? They are usually independent things, and one of the ways is to return this new string and hope for those who called to keep in the same variable that was passed as argument, which will not always happen, passing with ref
this is guaranteed, changed the reference of the string to a new string the variable used as argument will receive the change and point to the new string. So ref
is even more used to ensure that any change within a method is reflected in the calling method.
Already the out
was widely used for cases where you needed to return more than one value in a method, as it was possible to return only one you passed a reference to the method, without having anything of useful value and the method called took charge of putting a value there. It can always do otherwise, but it was done and more complicated, with the advent of tuples by value became easy and this mechanism should be much less used, unless to do some things on a lower level, how is the deconstruction of objects in tuples and interoperability with other languages like C for example.
Even there already exists the return ref
that makes the out
be less necessary.
Note that all are references, only have a slightly different guarantees.
If you’re not doing something lower-level, interoperable, or using an API that requires it or wants to perform more generally, you don’t need this.
The stack has always been more interesting to use, and so unlike Java, C# has always liked it more than the heap, now it’s liking more and needs to have these mechanisms, so C# gets closer to languages like C, C++, Rust, etc.
Useful for understanding heap and stack: https://answall.com/questions/3797/o-que-s%C3%A3o-e-onde-est%C3%A3o-o-stack-e-heap
– CypherPotato