Hi, I find the details of that answer to be helpful, but I still think that we must mention the most important aspect regarding performance and that is to trust the compiler when appropriate. Consider the following example:
string exampleStr = "Test";
RefArgExample(ref exampleStr);
// exampleStr is not needed after the above call to "RefArgExample", so the
// compiler could optimize and reuse it inside the function.
void RefArgExample(ref str)
{
// exampleStr passed as ref could be reused here and
// a new object needn't necessarily be created.
str = "Example string data";
}
void NonRefArgExample(str)
{
// Do something with str.
// ...
// ...
// str cannot be reused, so a 2nd object must be
// created - unless the compiler optimizes.
var str = "Example string data";
}
One might think that in some cases, passing an arg by ref can increase performance by eliminating the need to declare and create a new object in the function that accepts the ref arg. I.e. the ref arg serves as a no-cost local object. However, I think that even for non-ref args, a "smart" compiler could parse whether the passed arg is needed after the called function, and if not, could (under the hood) reuse the same string object inside the function rather than creating a new one.
Importantly I also note, that for tiny "objects" such as int, the ref could cost more and reduce performance (unless used as an output parameter), but for large objects, the ref arg could increase performance, unless the compiler would optimize regardless.
So, I think that what you are really telling us is to trust the compiler and use ref for what it is designed for, which is input-output parameters, and let the compiler engineers worry about the optimizations.