Они используются в основном для получения нескольких возвращаемых значений из вызова метода. Лично я склонен их не использовать. Если я хочу получить несколько возвращаемых значений из метода, я создам небольшой класс для их хранения.
ref и out используются, когда вы хотите что-то вернуть из метода в этом параметре. Насколько я помню, они оба на самом деле компилируются в один и тот же IL, но C # добавляет некоторые дополнительные вещи, так что вы должны быть конкретны.
Вот несколько примеров:
static void Main(string[] args)
{
string myString;
MyMethod0(myString);
Console.WriteLine(myString);
Console.ReadLine();
}
public static void MyMethod0(string param1)
{
param1 = "Hello";
}
Выше не скомпилируется, потому что myString никогда не инициализируется. Если myString инициализируется в string.Empty, то результатом программы будет пустая строка, потому что все, что делает MyMethod0, - это назначает новую строку локальной ссылке на param1.
static void Main(string[] args)
{
string myString;
MyMethod1(out myString);
Console.WriteLine(myString);
Console.ReadLine();
}
public static void MyMethod1(out string param1)
{
param1 = "Hello";
}
myString не инициализируется в методе Main, но программа выводит «Hello». Это связано с тем, что ссылка myString в методе Main обновляется из MyMethod1. MyMethod1 не ожидает, что param1 уже содержит что-либо, поэтому его можно оставить неинициализированным. Однако метод должен назначать что-либо.
static void Main(string[] args)
{
string myString;
MyMethod2(ref myString);
Console.WriteLine(myString);
Console.ReadLine();
}
public static void MyMethod2(ref string param1)
{
param1 = "Hello";
}
Это опять не скомпилируется. Это потому, что ref требует, чтобы myString в методе Main сначала инициализировался чем-то. Но, если метод Main изменен так, что myString инициализируется в string.Empty, тогда код скомпилируется, и на выходе будет Hello.
Таким образом, разница может быть использована с неинициализированным объектом, ref должен быть передан инициализированному объекту. И если вы передаете объект без ссылки на него, его нельзя заменить.
Просто чтобы прояснить: если передаваемый объект уже является ссылочным типом, то метод может обновить объект, и обновления будут отражены в вызывающем коде, однако ссылка на объект не может быть изменена. Поэтому, если я напишу такой код:
static void Main(string[] args)
{
string myString = "Hello";
MyMethod0(myString);
Console.WriteLine(myString);
Console.ReadLine();
}
public static void MyMethod0(string param1)
{
param1 = "World";
}
Вывод из программы будет Hello, а не World, потому что метод изменил только свою локальную копию ссылки, а не ссылку, которая была передана.
Надеюсь, это имеет смысл. Мое общее правило - просто не использовать их. Я чувствую, что это возвращение к предыдущим дням. (Но это только мое мнение)