The more I see ref used in production code, the more misuse I encounter and the more pain it causes me. I have come to hate this keyword, because from a framework-building s
Hypothetically, I'd guess that you might use a lot of ref/out arguments if you intended to mimic the architecture of older procedural software, for example old game engines and so on. I've scanned the source code of one, I think it was Duke Nukem 3D, and it's procedural with lots of subroutines modifying variables in place, and almost no functions. Obviously, you'd be unlikely to program like this for a real production application unless you had some specific aim in mind.
Any time you want to change the value of a value type - this happens a lot in cases where you want to efficiently update a pair of related values (i.e. rather than returning a struct containing two ints, you pass (ref int x, ref int y))
It's useful when you need efficient in-place algorithms on bignums.
I'm using ref quite often. Just think about functions with multiple return values. It doesn't make sense to create a return object (helper object) or even using hashtables for this purpose.
Example:
 getTreeNodeValues(ref selectedValue, ref selectedText);
Edit:
It's better to use out here - as commented.
 getTreeNodeValues(out selectedValue, out selectedText);
I'm using it for processing objects:
MyCar car = new MyCar { Name="TestCar"; Wieght=1000; }
UpdateWeight(ref car, 2000);
Another useful example in addition to swap<> is this:
Prompter.getString("Name ? ", ref firstName);
Prompter.getString("Lastname ? ", ref lastName);
Prompter.getString("Birthday ? ", ref firstName);
Prompter.getInt("Id ? ", ref id);
Prompter.getChar("Id type: <n = national id, p = passport, d = driver licence, m = medicare> \n? ", ref c);
public static class Prompter
{
    public static void getKey(string msg, ref string key)
    {
        Console.Write(msg);
        ConsoleKeyInfo cki = Console.ReadKey();
        string k = cki.Key.ToString();
        if (k.Length == 1)
            key = k;
    }
    public static void getChar(string msg, ref char key)
    {
        Console.Write(msg);
        key = Console.ReadKey().KeyChar;
        Console.WriteLine();
    }
    public static void getString(string msg, ref string s)
    {
        Console.Write(msg);
        string input = Console.ReadLine();
        if (input.Length != 0)
            s = input;
    }
    public static void getInt(string msg, ref int i)
    {
        int result;
        string s;
        Console.Write(msg);
        s = Console.ReadLine();
        int.TryParse(s, out result);
        if (result != 0)
            i = result;       
    }
    // not implemented yet
    public static string getDate(string msg)
    {
        // I should use DateTime.ParseExact(dateString, format, provider);
        throw new NotImplementedException();
    }    
}
Use out here it's not an option
Maybe when you have a struct (which is a value type):
struct Foo
{
    int i;
    public void Test()
    {
        i++;
    }
}
static void update(ref Foo foo)
{
    foo.Test();
}
and
Foo b = new Foo();
update(ref b);
Here you would to use two-parameters with out like:
static void update(Foo foo, out Foo outFoo) //Yes I know you could return one foo instead of a out but look below
{
    foo.Test();
    outFoo = foo;
}
imaging the method having more than one Foo then you would get twice the parameters with out versus ref. An alternative is to return a N-tuple. I don't have a real-world example on when to use this stuff.
Add on: Different .TryParse methods could also have avoided out if they returned Nullable<T> instead which essentially is a tuple of boolean * T.