The difference between reference and value types can seem very subtle, and despite the abstract nature of memory management in .NET I think people who have a background in C or C++ have an easier time understanding this. I'll take a stab at it, since I'm waiting for a batch to run

.
[00000000] <-- memory location
Here we have a location in the computer's memory. You can see that it is 4 bytes wide, so it is a dword and able to store values between -2 billion and something and +2 billion and something.
Locations in memory aren't very memorable, so let's create another one, but give it a name:
long l;
[00000000] <-- l refers to this memory location
l = 1;
[00000100] <-- l = 1 (on little endian platforms like Intel)
l = 2;
[00000200] <-- l = 2 (the 1 is overwritten)
Now, since a memory location can hold a number, and the address of a location in memory _is_ a number, it follows that a memory location can hold the address of another memory location. Voila, le pointer is born. But since this is C#, let's not call the location that holds the address a pointer. Instead let's call it a reference.
MyObject o = new MyObject();
This statement can be broken down as follows:
1. Allocate the variable o, of type MyObject, on the runtime stack.
2. Allocate enough memory for a MyObject on the heap and save the address.
3. Call MyObject's constructor to initialize the memory.
4. Assign the saved address to o.
In C++ I would not have said, in step 1, "of type MyObject", because in C++ objects, references, and pointers are different addressable types. I would have said "of type reference to MyObject" or "of type pointer to MyObject." But in C# references limited independent addressability. You can only initialize them and assign to them. When you assign to them, unless the type refered to has defined assigment semantics, you are replacing the address of one object with the address of another (essentially, C# gurus don't flame me). Anything else you do operates through the reference on the object it refers to.
So what happens in method calls? Again this is something that I think C/C++ people have an easier time grasping. For a long time now microcomputers have passed arguments to methods in registers or on the stack. That is, when a method is called all the arguments to it are _copied to_ cpu registers or memory locations in the runtime stack. The called method then pops them off the stack or gets them from the registers and uses them. Two important things: 1) you can only pass scalar values or collections of scalar values (structs) on the stack (I am not sure whether an optimizing compiler will pass a small struct in registers); and 2) the values are copied to the stack. The originals stay where they are and are unaffected by whatever the called method does.
So how do you pass a complex object like, oh, FileStream to a method? By reference. A reference to an object is, internally, a scalar value. It's an address, and can be pushed onto the stack or into a register. In the called method, when that value is retrieved, whatever it done to it affects the object it refers to (see the rule about what you can do with references, above). That is, everything except assignment. If you take that reference in the called method, and you assign it to refer to another object, then allow the method to return, will the caller see that the reference it passed now refers to a new object?
The answer is no, it won't. Because the reference itself is a scalar value that was _copied to_ the stack or a register when the method is called. Changes to that reference in the called method act on the copy that was passed.
So to sum up, the ref keyword used with a scalar argument in a call to a method tells the compiler not to pass a copy of the value itself, but rather to create a reference to that value and pass that instead. The reference is anonymous, and you can't address it or manipulate it directly. But when you do something to it in the called method you are altering the original memory location that was passed by reference, and not a copy as would be the ordinary case.