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

640

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

public void myFunction(ref MyClass someClass)

и

public void myFunction(out MyClass someClass)

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

  • 55
    Вы: Мне нужно передать объект, чтобы он мог быть изменен. Похоже, MyClass будет типом class , то есть ссылочным типом. В этом случае передаваемый вами объект может быть изменен myFunction даже без ключевого слова ref / out . myFunction получит новую ссылку, которая указывает на тот же объект, и он может изменять этот же объект столько, сколько он хочет. В отличие от ключевого слова ref , myFunction получит одну и ту же ссылку на тот же объект. Это было бы важно, только если бы myFunction изменила ссылку, чтобы указать на другой объект.
  • 2
    Я озадачен количеством запутанных ответов здесь, когда @ AnthonyKolesov's совершенно безупречен.
Показать ещё 3 комментария
Теги:
ref
reference
keyword
out

24 ответа

845
Лучший ответ

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

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

  • 246
    Еще одна интересная особенность out - это то, что функция должна присваивать параметр out. Не разрешается оставлять это без назначения.
  • 6
    'ref' применим только к типу значения? Поскольку ссылочный тип всегда передается по ссылке.
Показать ещё 8 комментариев
396

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

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

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

  • Значение не установлено и не может быть прочитано методом до его установки.
  • Метод должен установить его перед возвратом.
  • 27
    Этот ответ наиболее четко и кратко объясняет ограничения, налагаемые компилятором при использовании ключевого слова out, а не ключевого слова ref.
  • 5
    Из MSDN: параметр ref должен быть инициализирован перед использованием, в то время как параметр out не должен явно инициализироваться перед передачей, а любое предыдущее значение игнорируется.
Показать ещё 2 комментария
112

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

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

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

  • 51
    Реф Дом написал бы карандашом отчет, чтобы Питер мог его изменить
  • 5
    @ Дибстер, ты знаешь, эта метафора ничего не сделала с тобой, почему ты так мучаешь это? ;)
Показать ещё 3 комментария
42

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

Я думаю, мы понимаем, как работают типы значений? Типы значений (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
  • 0
    Вы имеете в виду, в конце концов (в случае ссылки) есть только одна ссылка на данные, но два псевдонима для них. Правильно?
  • 3
    Проголосовал за четкое объяснение. Но я думаю, что это не отвечает на вопрос, поскольку не объясняет разницу между параметрами ref и out .
Показать ещё 2 комментария
24

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

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

  • 0
    не совсем, как принятый ответ ref, если направленный и бесполезный, игнорируя значения-типы, если не передан обратно.
  • 0
    @kenny: Не могли бы вы немного уточнить, то есть, какие слова вы бы изменили, чтобы поддержать дух ответа, но устранить неточность, которую вы ощущаете? Мой ответ не является сумасшедшим предположением новичка, но спешка (краткость, опечатки) в вашем комментарии, кажется, предполагает, что это так. Цель состоит в том, чтобы предоставить способ думать о разнице с наименьшим количеством слов.
Показать ещё 6 комментариев
9

из

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

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

исй:

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

  • Вам нужно инициализировать переменную до вызова функции.
  • Не обязательно назначать какое-либо значение параметру ref в методе. Если вы не изменяете значение, в чем состоит необходимость отметить его как "ref"?
  • 0
    «В C # метод может возвращать только одно значение. Если вы хотите вернуть более одного значения, вы можете использовать ключевое слово out». Мы также можем использовать «ref» для возврата значения. Таким образом, мы можем использовать как ref, так и out, если хотим вернуть несколько значений из метода?
  • 1
    В C # 7 вы можете вернуть несколько значений с помощью ValueTuples.
9

Расширение примера 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;
    }
5

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

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

Поскольку вы передаете ссылочный тип (класс), нет необходимости использовать 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, если вы хотите изменить объект внутри своего метода.

  • 5
    Это работает, только если новый объект не создан и не возвращен. Когда создается новый объект, ссылка на старый объект будет потеряна.
  • 7
    Это неправильно - попробуйте следующее: добавьте someObject = null в конец выполнения Bar . Ваш код будет работать нормально, так как только ссылка Bar на экземпляр была обнулена. Теперь измените Bar на Bar(ref MyClass someObject) и выполните снова - вы получите NullReferenceException поскольку NullReferenceException Foo на экземпляр также была обнулена.
4

"Бейкер"

Это потому, что первый изменит вашу ссылку на строку, чтобы указать на "Бейкер". Изменение ссылки возможно, потому что вы передали ее через ключевое слово 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)

  • 1
    Именно так. Поэтому не совсем верно говорить «Поскольку вы передаете ссылочный тип (класс), нет необходимости использовать ref».
  • 0
    Теоретически это правильно сказать, потому что он написал «чтобы его можно было изменить», что невозможно в строках. Но из-за неизменяемых объектов «ref» и «out» очень полезны и для ссылочных типов! (.Net содержит много неизменных классов!)
Показать ещё 2 комментария
2

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

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

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

2

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);
  • 1
    Вы можете объявить переменную inline: out double Half_nbr .
2

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


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

Прочитайте здесь.

2

Из: Оператор 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();

      }
   }
}
1
 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 в этой функции

1

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

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

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

0

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

(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), чтобы создать объект в куче и сохранить его начальный адрес в переменной аргумента. Никакая неинициализированная ошибка не будет сброшена, и любая предыдущая сохраненная ссылка будет потеряна.

0

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)
    {

    }
}
  • 4
    s1 по умолчанию инициализируется нулем. потому что поля инициализируются со своим значением по умолчанию, а значение по умолчанию ссылочного типа равно нулю. вот почему это никогда не вызывает никаких проблем.
0

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

0

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).

0

С точки зрения метода, который получает параметр, разница между 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.

0

Ниже я показал пример, используя как 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; }
} 
-2

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

        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 и самой строки, поскольку строка является ссылочным типом, который делает вид, но не является типом значения.

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

  • 5
    Добро пожаловать в переполнение стека, Эдвин. Насколько я знаю, строки передаются по ссылке, как и любой другой объект. Вы можете быть сбиты с толку, потому что строки являются неизменяемыми объектами, поэтому не так очевидно, что они передаются по ссылке. Представьте, что в строке есть метод с именем Capitalize() , который изменяет содержимое строки на заглавные буквы. Если вы тогда заменили свою строку a = "testing"; с a.Capitalize(); , тогда ваш вывод будет "Привет", а не "Привет". Одним из преимуществ неизменяемых типов является то, что вы можете передавать ссылки и не беспокоиться о том, что другой код изменит значение.
  • 2
    Существует три основных типа семантики, которые может представлять тип: изменяемая ссылочная семантика, изменяемая семантика значений и неизменяемая семантика. Рассмотрим переменные x и y типа T, которые имеют поле или свойство m, и предположим, что x скопирован в y. Если T имеет ссылочную семантику, изменения в xm будут наблюдаться ym. Если T имеет семантику значений, можно изменить xm, не влияя на ym. Если T имеет неизменную семантику, ни xm, ни ym никогда не изменятся. Неизменная семантика может быть смоделирована либо объектами ссылки, либо объектами значений. Строки являются неизменяемыми ссылочными объектами.
-2

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

Например,

    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.

  • 6
    Хотя все здесь в значительной степени верно, на самом деле это не объясняет разницу между значением по ссылке или вне. В лучшем случае он наполовину объясняет разницу между ссылочным и ценностно-неизменным типами.
  • 0
    Если вы хотите, чтобы этот код писал cat, передайте этот объект вместе с ключом 'ref' следующим образом: public static void Bar (ref MyClass someObject), Bar (ref myObject);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню