In a call like
F(ref a); // ByRef parameter
the variable a is "used directly" by the body of method F. There's only one storage location. If the method F assigns to its parameter, that assignment will be visible to everyone who can see a, immediately. And conversely, if someone (outside F) assigns to a while method F is running, then the parameter of F will change to the new object "all of a sudden".
On the other hand, in a call like
F(a); // normal value parameter
the variable a is first copied to a new variable, and then the new variable is used inside F. Now if the type of the parameter of F is a value type (like a struct or enum), the copy is done by value. So the entire data is copied. But if the type of the parameter is a reference type (class (including array type), interface, delegate), the copy of a involves a copy of the reference only.
To check your understanding of the value parameter case with a class type parameter, figure out what these methods do:
static void F1(List<int> list>) // no ref modifier
{
list.Clear();
}
static void F2(List<int> list>) // no ref modifier
{
list = new List<int>();
}
Here's some possibly interesting example with ref:
static void G(ref string a, ref string b)
{
if (string.Equals(a, b))
b += "_unique";
// Is it now safe to say that a and b are distinct?
// No. Anyone could have changed either a or b by now.
// For example, a and b could "alias" public fields visisble to other threads.
}
As an example of the use of G above, consider the code var x = "initial"; G(ref x, ref x); in which case a will change together with b inside the method G.