Какая разница между ключевыми словами "ref" и "out"?

Я создаю функцию, в которой мне нужно передать объект, чтобы он мог быть изменен функцией. В чем разница между:

public void myFunction(ref MyClass someClass)

и

public void myFunction(out MyClass someClass)

Что я должен использовать и почему?

Ответ 1

ref сообщает компилятору, что объект инициализирован перед входом в функцию, а out сообщает компилятору, что объект будет инициализирован внутри функции.

Итак, пока ref является двусторонним, out недоступен.

Ответ 2

Модификатор ref означает, что:

  • Значение уже установлено и
  • Метод может читать и изменять его.

Модификатор out означает, что:

  • Значение не установлено и не может быть прочитано методом до его установки.
  • Метод должен установить его перед возвратом.

Ответ 3

Скажем, "Дом" появляется в кабинете Питера о записке о отчетах TPS.

Если бы Dom был аргументом ref, у него была бы напечатанная копия напоминания.

Если бы Дом был аргументом, он заставил бы Питера распечатать новую копию записки, чтобы он взял с собой.

Ответ 4

Я собираюсь попробовать свои силы в объяснении:

Я думаю, мы понимаем, как работают типы значений? Типы значений (int, long, struct и т.д.). Когда вы отправляете их в функцию без команды ref, она копирует данные. Все, что вы делаете с этими данными в функции, влияет только на копию, а не на оригинал. Команда ref отправляет данные ACTUAL, и любые изменения будут влиять на данные вне функции.

Хорошо на запутанную часть, ссылочные типы:

Позволяет создать ссылочный тип:

List<string> someobject = new List<string>()

Когда вы обновляете какой-то объект, создаются две части:

  • Блок памяти, который содержит данные для некоторого объекта.
  • Ссылка (указатель) на этот блок данных.

Теперь, когда вы отправляете какой-либо объект в метод без ссылки на него, COPIES ссылка указатель, а не данные. Итак, теперь у вас есть это:

(outside method) reference1 => someobject
(inside method)  reference2 => someobject

Две ссылки, указывающие на один и тот же объект. Если вы измените свойство на каком-то объекте, используя reference2, оно повлияет на те же данные, на которые ссылается reference1.

 (inside method)  reference2.Add("SomeString");
 (outside method) reference1[0] == "SomeString"   //this is true

Если вы вычеркиваете ссылку2 или указываете ее на новые данные, это не повлияет на reference1, а не на ссылку данных1.

(inside method) reference2 = new List<string>();
(outside method) reference1 != null; reference1[0] == "SomeString" //this is true

The references are now pointing like this:
reference2 => new List<string>()
reference1 => someobject

Теперь что происходит, когда вы отправляете какой-либо объект по ссылке на метод? фактическая ссылка на какой-то объект отправляется методу. Итак, теперь у вас есть только одна ссылка на данные:

(outside method) reference1 => someobject;
(inside method)  reference1 => someobject;

Но что это значит? Он действует точно так же, как отправка некоторого объекта не по ссылке, за исключением двух основных:

1) Когда вы удаляете ссылку внутри метода, она будет нулевым вне метода.

 (inside method)  reference1 = null;
 (outside method) reference1 == null;  //true

2) Теперь вы можете указать ссылку на совершенно другое местоположение данных, а ссылка вне функции теперь укажет на новое местоположение данных.

 (inside method)  reference1 = new List<string>();
 (outside method) reference1.Count == 0; //this is true

Ответ 5

ref находится в и вне.

Вы должны использовать out по своему усмотрению, где это достаточно для ваших требований.

Ответ 6

из

В С# метод может возвращать только одно значение. Если вам нравится возвращать более одного значения, вы можете использовать ключевое слово out. Выходной модификатор возвращается как возвращаемый по ссылке. Самый простой ответ заключается в том, что ключевое слово "out" используется для получения значения из метода.

  • Вам не нужно инициализировать значение в вызывающей функции.
  • Вы должны назначить значение в вызываемой функции, иначе компилятор сообщит об ошибке.

исй:

В С#, когда вы передаете тип значения, такой как int, float, double и т.д. в качестве аргумента параметра метода, он передается по значению. Поэтому, если вы изменяете значение параметра, это не влияет на аргумент в вызове метода. Но если вы помечаете параметр ключевым словом "ref", он будет отображаться в фактической переменной.

  • Вам нужно инициализировать переменную до вызова функции.
  • Не обязательно назначать какое-либо значение параметру ref в методе. Если вы не изменяете значение, в чем состоит необходимость отметить его как "ref"?

Ответ 7

Расширение примера Dog, Cat. Второй метод с ref изменяет объект, на который ссылается вызывающий. Отсюда "Кот"!!!

    public static void Foo()
    {
        MyClass myObject = new MyClass();
        myObject.Name = "Dog";
        Bar(myObject);
        Console.WriteLine(myObject.Name); // Writes "Dog". 
        Bar(ref myObject);
        Console.WriteLine(myObject.Name); // Writes "Cat". 
    }

    public static void Bar(MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

    public static void Bar(ref MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

Ответ 8

Поскольку вы передаете ссылочный тип (класс), нет необходимости использовать ref, потому что по умолчанию передается только ссылка для фактического объекта, и поэтому вы всегда меняете объект за ссылкой.

Пример:

public void Foo()
{
    MyClass myObject = new MyClass();
    myObject.Name = "Dog";
    Bar(myObject);
    Console.WriteLine(myObject.Name); // Writes "Cat".
}

public void Bar(MyClass someObject)
{
    someObject.Name = "Cat";
}

Пока вы проходите в классе, вам не нужно использовать ref, если вы хотите изменить объект внутри своего метода.

Ответ 9

ref и out ведут себя аналогично, за исключением следующих различий.

  • ref переменная должна быть инициализирована перед использованием. out переменная может использоваться без назначения
  • out параметр должен рассматриваться как неназначенное значение функцией, которая его использует. Таким образом, мы можем использовать инициализированный параметр out в вызывающем коде, но значение будет потеряно при выполнении функции.

Ответ 10

Для тех, кто учится на примере (как я), вот что Энтони Колесов говорит.

Я создал несколько минимальных примеров ref, out и других, чтобы проиллюстрировать это. Я не освещаю лучшие практики, просто примеры, чтобы понять различия.

https://gist.github.com/2upmedia/6d98a57b68d849ee7091

Ответ 11

"Бейкер"

Это потому, что первый изменит вашу ссылку на строку, чтобы указать на "Бейкер". Изменение ссылки возможно, потому что вы передали ее через ключевое слово ref (= > ссылку на ссылку на строку). Второй вызов получает копию ссылки на строку.

Строка

сначала выглядит как-то особенным. Но строка - это только ссылочный класс, и если вы определяете

string s = "Able";

то s является ссылкой на класс строк, который содержит текст "Able"! Другое назначение одной переменной с помощью

s = "Baker";

не изменяет исходную строку, а просто создает новый экземпляр и позволяет s указывать на этот экземпляр!

Вы можете попробовать его с помощью следующего небольшого примера кода:

string s = "Able";
string s2 = s;
s = "Baker";
Console.WriteLine(s2);

Чего вы ожидаете? То, что вы получите, по-прежнему "Able", потому что вы просто установите ссылку в s на другой экземпляр, в то время как s2 указывает на исходный экземпляр.

EDIT: строка также является неизменной, что означает, что просто нет метода или свойства, которое модифицирует существующий экземпляр строки (вы можете попытаться найти его в документах, но вы не заплатите никаких:-)). Все методы манипуляции строками возвращают новый экземпляр строки! (Вот почему вы часто получаете лучшую производительность при использовании класса StringBuilder)

Ответ 12

ref означает, что значение в параметре ref уже установлено, метод может прочитать и изменить его. Использование ключевого слова ref - это то же самое, что сказать, что вызывающая сторона отвечает за инициализацию значения параметра.


out сообщает компилятору, что инициализация объекта является обязанностью функция, которую функция должна назначить выходному параметру. Это не позволило оставить его без назначения.

Ответ 13

Из: Оператор return может использоваться для возврата только одного значения из функции. Однако, используя выходные параметры, вы можете вернуть два значения из функции. Выходные параметры похожи на контрольные параметры, за исключением того, что они переносят данные из метода, а не в него.

Следующий пример иллюстрирует это:

using System;

namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void getValue(out int x )
      {
         int temp = 5;
         x = temp;
      }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;

         Console.WriteLine("Before method call, value of a : {0}", a);

         /* calling a function to get the value */
         n.getValue(out a);

         Console.WriteLine("After method call, value of a : {0}", a);
         Console.ReadLine();

      }
   }
}

ссылка Контрольный параметр - это ссылка на ячейку памяти переменной. Когда вы передаете параметры по ссылке, в отличие от параметров параметров, для этих параметров не создается новое хранилище. Ссылочные параметры представляют собой ту же ячейку памяти, что и фактические параметры, которые предоставляются этому методу.

В С# вы указываете ссылочные параметры с помощью ключевого слова ref. Следующий пример демонстрирует это:

using System;
namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void swap(ref int x, ref int y)
      {
         int temp;

         temp = x; /* save the value of x */
         x = y;   /* put y into x */
         y = temp; /* put temp into y */
       }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;
         int b = 200;

         Console.WriteLine("Before swap, value of a : {0}", a);
         Console.WriteLine("Before swap, value of b : {0}", b);

         /* calling a function to swap the values */
         n.swap(ref a, ref b);

         Console.WriteLine("After swap, value of a : {0}", a);
         Console.WriteLine("After swap, value of b : {0}", b);

         Console.ReadLine();

      }
   }
}

Ответ 14

ref и out работают так же, как передача по ссылкам и передача указателями, как на С++.

Для ref аргумент должен быть объявлен и инициализирован.

Для out аргумент должен быть объявлен, но может быть или не быть инициализирован

        double nbr = 6; // if not initialized we get error
        double dd = doit.square(ref nbr);

        double Half_nbr ; // fine as passed by out, but inside the calling  method you initialize it
        doit.math_routines(nbr, out Half_nbr);

Ответ 15

Время разработки:

(1) Мы создаем вызывающий метод Main()

(2) он создает объект List (который является объектом ссылочного типа) и сохраняет его в переменной myList.

public sealed class Program 
{
    public static Main() 
    {
        List<int> myList = new List<int>();

Во время выполнения:

(3) Runtime выделяет память в стеке на # 00, достаточно широкую для хранения адреса (# 00 = myList, так как имена переменных - это просто псевдонимы для мест памяти)

(4) Runtime создает объект списка в куче в ячейке памяти #FF (например, все эти адреса)

(5) Runtime затем сохранит начальный адреС#FF объекта в # 00 (или в словах, сохранит ссылку объекта List в указателе myList)

Назад к времени разработки

(6) Затем мы передаем объект List в качестве аргумента myParamList вызываемому методу modifyMyList и присваиваем ему новый объект List

List<int> myList = new List<int>();

List<int> newList = ModifyMyList(myList)

public List<int> ModifyMyList(List<int> myParamList){
     myParamList = new List<int>();
     return myParamList;
}

Во время выполнения:

(7) Runtime запускает процедуру вызова для вызываемого метода и как часть ее, проверяет тип параметров.

(8) При поиске ссылочного типа он выделяет память в стеке на # 04 для сглаживания переменной параметра myParamList.

(9) Затем он сохраняет в нем значение #FF.

(10) Runtime создает объект списка в куче в ячейке памяти # 004 и заменяет #FF в # 04 этим значением (или разыменовал исходный объект List и указал на новый объект List в этом методе)

Адрес в # 00 не изменяется и сохраняет ссылку на #FF (или исходный указатель myList не нарушен).


Ключевое слово ref - это директива компилятора, позволяющая пропустить генерацию кода времени выполнения для (8) и (9), что означает, что для параметров метода не будет выделено куча. Он будет использовать оригинальный указатель # 00 для работы с объектом в #FF. Если исходный указатель не инициализирован, среда выполнения перестанет жаловаться, что она не работает, поскольку переменная не инициализирована

Ключевое слово out - это директива компилятора, которая в значительной степени совпадает с ref с небольшой модификацией (9) и (10). Компилятор ожидает, что аргумент не инициализирован и продолжит (8), (4) и (5), чтобы создать объект в куче и сохранить его начальный адрес в переменной аргумента. Никакая неинициализированная ошибка не будет сброшена, и любая предыдущая сохраненная ссылка будет потеряна.

Ответ 16

Они почти одинаковы - единственное отличие состоит в том, что переменную, которую вы передаете как параметр out, не нужно инициализировать, а метод, использующий параметр ref, должен установить что-то.

int x;    Foo(out x); // OK 
int y;    Foo(ref y); // Error

Параметры Ref для данных, которые могут быть изменены, вне параметров для данных, которые являются дополнительным выходом для функции (например, int.TryParse), которые уже используют возвращаемое значение для чего-то.

Ответ 17

Ниже я показал пример, используя как Ref, так и out. Теперь вы будете очищены от реф и вы.

В приведенном ниже примере, когда я комментирую //myRefObj = new myClass {Name = "ref external called!!" }; строка, получит сообщение об ошибке "Использование неназначенной локальной переменной myRefObj" , но такой ошибки нет в вне.

Где использовать Ref: когда мы вызываем процедуру с параметром in, и тот же параметр будет использоваться для хранения вывода этого proc.

Где использовать Out:, когда мы вызываем процедуру без параметра, и тот же параметр будет использоваться для возврата значения из этого proc. Также обратите внимание на выход

public partial class refAndOutUse : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        myClass myRefObj;
        myRefObj = new myClass { Name = "ref outside called!!  <br/>" };
        myRefFunction(ref myRefObj);
        Response.Write(myRefObj.Name); //ref inside function

        myClass myOutObj;
        myOutFunction(out myOutObj);
        Response.Write(myOutObj.Name); //out inside function
    }

    void myRefFunction(ref myClass refObj)
    {
        refObj.Name = "ref inside function <br/>";
        Response.Write(refObj.Name); //ref inside function
    }
    void myOutFunction(out myClass outObj)
    {
        outObj = new myClass { Name = "out inside function <br/>" }; 
        Response.Write(outObj.Name); //out inside function
    }
}

public class myClass
{
    public string Name { get; set; }
} 

Ответ 18

 public static void Main(string[] args)
    {
        //int a=10;
        //change(ref a);
        //Console.WriteLine(a);
        // Console.Read();

        int b;
        change2(out b);
        Console.WriteLine(b);
        Console.Read();
    }
    // static void change(ref int a)
    //{
    //    a = 20;
    //}

     static void change2(out int b)
     {
         b = 20;
     }

вы можете проверить этот код, он будет описывать вам ваш полный differnce когда вы используете "ref", это означает, что u уже инициализирует эту строку int/string

но  когда вы используете "вне", он работает в обоих условиях, и инициализирует эту строку int/string или нет но u должен инициализировать эту int/string в этой функции

Ответ 19

Ref: Ключевое слово ref используется для передачи аргумента в качестве ссылки. Это означает, что когда значение этого параметра изменяется в методе, оно получает отражение в вызывающем методе. Аргумент, который передается с использованием ключевого слова ref, должен быть инициализирован в вызывающем методе до его передачи вызываемому методу.

Из: Ключевое слово out также используется для передачи аргумента, такого как ключевое слово ref, но аргумент может передаваться без присвоения ему какого-либо значения. Аргумент, который передается с использованием ключевого слова out, должен быть инициализирован в вызываемом методе до того, как он вернется к методу вызова.

public class Example
{
 public static void Main() 
 {
 int val1 = 0; //must be initialized 
 int val2; //optional

 Example1(ref val1);
 Console.WriteLine(val1); 

 Example2(out val2);
 Console.WriteLine(val2); 
 }

 static void Example1(ref int value) 
 {
 value = 1;
 }
 static void Example2(out int value) 
 {
 value = 2; 
 }
}

/* Output     1     2     

Ref и out при перегрузке метода

Оба метода ref и out не могут использоваться при перегрузке метода одновременно. Тем не менее, ref и out обрабатываются по-разному во время выполнения, но во время компиляции они обрабатываются одинаково (CLR не делает различий между ними, пока он создал IL для ref и out).

Ответ 20

Помимо возможности переназначения чужой переменной другому экземпляру класса, возврата нескольких значений и т.д., с помощью ref или out позволяет кому-то еще знать, что вам нужно от них и что вы собираетесь делать переменная, которую они предоставляют

  • Вам не нужно ref или out, если все, что вы собираетесь сделать, это изменить вещи внутри экземпляра MyClass, который передается в аргументе someClass.

    • Вызывающий метод увидит изменения, такие как someClass.Message = "Hello World", используете ли вы ref, out или ничего
    • Запись someClass = new MyClass() внутри myFunction(someClass) заменяет объект, видимый someClass только в области действия метода myFunction. Вызывающий метод все еще знает об оригинальном экземпляре MyClass, который он создал и передал вашему методу
  • Вам нужно ref или out, если вы планируете заменить someClass на совершенно новый объект и хотите, чтобы вызывающий метод увидел ваши изменения

    • Запись someClass = new MyClass() внутри myFunction(out someClass) изменяет объект, видимый методом, который вызвал myFunction

Существуют другие программисты

И они хотят знать, что вы собираетесь делать со своими данными. Представьте, что вы пишете библиотеку, которая будет использоваться миллионами разработчиков. Вы хотите, чтобы они знали, что вы собираетесь делать со своими переменными, когда они вызывают ваши методы

  • Использование ref приводит к выражению "Передайте переменную, назначенную некоторому значению, когда вы вызываете мой метод. Имейте в виду, что я могу полностью заменить его на что-то другое в ходе моего метода. Не ожидайте, что ваша переменная будет указывать на старый объект, когда я закончу "

  • Использование out делает утверждение "Передать переменную-заполнитель моему методу. Неважно, имеет ли оно значение или нет; компилятор заставит меня присвоить ему новое значение. Я абсолютно гарантирую, что объект указал на от вашей переменной до того, как вы вызвали мой метод, к тому времени, когда я закончу, все будет иначе

Кстати, в С# 7.2 тоже есть модификатор in

И это предотвращает замену метода переданным экземпляром для другого экземпляра. Подумайте об этом, как если бы вы сказали тем миллионам разработчиков: "Передайте мне исходную ссылку на переменную, и я обещаю не менять ваши тщательно созданные данные на что-то другое". У in есть некоторые особенности, и в некоторых случаях, например, когда может потребоваться неявное преобразование, чтобы сделать ваше короткое соединение совместимым с in int, компилятор временно сделает int, расширит ваше короткое замыкание, передаст его по ссылке и завершит работу. вверх. Это может быть сделано, потому что вы заявили, что не будете с этим связываться.


Microsoft сделала это с помощью методов .TryParse для числовых типов:

int i = 98234957;
bool success = int.TryParse("123", out i);

Пометив параметр как out, они здесь активно декларируют: "мы определенно собираемся заменить ваше кропотливое значение 98234957 на что-то другое"

Конечно, они вроде как должны, для таких вещей, как синтаксический анализ типов значений, потому что если бы методу parse не было разрешено поменять тип значения на что-то другое, это не сработало бы очень хорошо... Но представьте, что в некоторых есть какой-то фиктивный метод создаваемая вами библиотека:

public void PoorlyNamedMethod(out SomeClass x)

Вы можете видеть его как out, и, таким образом, вы можете знать, что если вы часами работаете над цифрами, создавая идеальный SomeClass:

SomeClass x = SpendHoursMakingMeAPerfectSomeClass();
//now give it to the library
PoorlyNamedMethod(out x);

Ну, это была пустая трата времени, потратить все эти часы, чтобы сделать этот идеальный урок. Это определенно будет отброшено и заменено PoorlyNamedMethod

Ответ 21

С точки зрения метода, который получает параметр, разница между ref и out заключается в том, что С# требует, чтобы методы возвращались к каждому параметру out и не должны ничего делать с таким параметром, за исключением передачи его как параметра out или записи на него, пока он не будет передан как параметр out другому методу или не написан непосредственно. Обратите внимание, что некоторые другие языки не налагают таких требований; виртуальный или интерфейсный метод, объявленный в С# с параметром out, может быть переопределен на другом языке, который не налагает никаких особых ограничений на такие параметры.

С точки зрения вызывающего, С# во многих случаях предполагает, что вызов метода с параметром out приведет к записи переданной переменной без предварительного чтения. Это предположение может быть неверным при вызове методов, написанных на других языках. Например:

struct MyStruct
{
   ...
   myStruct(IDictionary<int, MyStruct> d)
   {
     d.TryGetValue(23, out this);
   }
}

Если myDictionary идентифицирует реализацию IDictionary<TKey,TValue>, написанную на языке, отличном от С#, хотя MyStruct s = new MyStruct(myDictionary); выглядит как присвоение, он потенциально может оставить s немодифицированным.

Обратите внимание, что конструкторы, написанные на VB.NET, в отличие от С#, не делают никаких предположений о том, будут ли вызываемые методы изменять любые параметры out и безоговорочно очищать все поля. Нечетное поведение, упомянутое выше, не будет происходить с кодом, написанным полностью в VB или полностью на С#, но может произойти, когда код, написанный на С#, вызывает метод, написанный на VB.NET.

Ответ 22

Если вы хотите передать свой параметр как ref, вы должны инициализировать его перед передачей параметра в функцию else. Компилятор сам покажет ошибку. Но в случае параметра out вам не нужно инициализировать параметр объекта перед передачей это к методу. Вы можете инициализировать объект в самом вызывающем методе.

Ответ 23

ref здесь хорошо объяснено, но имейте в виду, что ref может быть вызван с неинициализированным объектом.

См. этот пример - обратите внимание на область действия s1

public class Class1
{
    // uninitialized
    private string s1;

    public Class1()
    {
        // no issue here..
        RefEater(ref s1);

        // Error CS0165 Use of unassigned local variable 's2'
        //string s2;
        //RefEater(ref s2);
    }

    private void RefEater(ref string s)
    {

    }
}

Ответ 24

Чтобы проиллюстрировать множество превосходных объяснений, я разработал следующее консольное приложение:

using System;
using System.Collections.Generic;

namespace CSharpDemos
{
  class Program
  {
    static void Main(string[] args)
    {
      List<string> StringList = new List<string> { "Hello" };
      List<string> StringListRef = new List<string> { "Hallo" };

      AppendWorld(StringList);
      Console.WriteLine(StringList[0] + StringList[1]);

      HalloWelt(ref StringListRef);
      Console.WriteLine(StringListRef[0] + StringListRef[1]);

      CiaoMondo(out List<string> StringListOut);
      Console.WriteLine(StringListOut[0] + StringListOut[1]);
    }

    static void AppendWorld(List<string> LiStri)
    {
      LiStri.Add(" World!");
      LiStri = new List<string> { "¡Hola", " Mundo!" };
      Console.WriteLine(LiStri[0] + LiStri[1]);
    }

    static void HalloWelt(ref List<string> LiStriRef)
     { LiStriRef = new List<string> { LiStriRef[0], " Welt!" }; }

    static void CiaoMondo(out List<string> LiStriOut)
     { LiStriOut = new List<string> { "Ciao", " Mondo!" }; }
   }
}
/*Output:
¡Hola Mundo!
Hello World!
Hallo Welt!
Ciao Mondo!
*/
  • AppendWorld: передается копия StringList с именем LiStri. На начало метода, эта копия ссылается на исходный список и поэтому может быть использован для изменения этого списка. Более поздние ссылки LiStri другой объект List<string> внутри метода, который не влияет оригинальный список.

  • HalloWelt: LiStriRef является псевдонимом уже инициализированного ListStringRef. Переданный объект List<string> используется для инициализации новый, поэтому ref был необходим.

  • CiaoMondo: LiStriOut является псевдонимом ListStringOut и должен быть инициализируется.

Таким образом, если метод просто изменяет объект, на который ссылается переданная переменная, компилятор не позволит вам использовать out, и вам не следует использовать ref, потому что это может сбить с толку не компилятор, а читателя кода. Если метод заставит переданный аргумент ссылаться на другой объект, используйте ref для уже инициализированного объекта и out для методов, которые должны инициализировать новый объект для переданного аргумента. Кроме того, ref и out ведут себя одинаково.

Ответ 25

Хорошо помните, что контрольный параметр, который передается внутри функции, непосредственно обрабатывается.

Например,

    public class MyClass
    {
        public string Name { get; set; }
    }

    public void Foo()
    {
        MyClass myObject = new MyClass();
        myObject.Name = "Dog";
        Bar(myObject);
        Console.WriteLine(myObject.Name); // Writes "Dog".
    }

    public void Bar(MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

Это будет писать Dog, а не Cat. Следовательно, вы должны непосредственно работать с someObject.

Ответ 26

Возможно, я не настолько хорош в этом, но, конечно, строки (даже если они являются технически ссылочными типами и живут в куче) передаются по значению, а не по ссылке?

        string a = "Hello";

        string b = "goodbye";

        b = a; //attempt to make b point to a, won't work.

        a = "testing";

        Console.WriteLine(b); //this will produce "hello", NOT "testing"!!!!

Вот почему вам нужен ref, если вы хотите, чтобы изменения существовали вне области действия функции, создающей их, вы не передаете ссылку иначе.

Насколько мне известно, вам нужен только ref для типов structs/value и самой строки, поскольку строка является ссылочным типом, который делает вид, но не является типом значения.

Я мог быть совершенно неправ здесь, но я новичок.