Аргументы ref

Передача параметров по ссылке отмечается помещением модификатора ref перед типом параметра в списке параметров метода. Когда переменная передается по ссылке, новая копия этой переменной не создается, и эту переменную из вызывающего метода напрямую затрагивают все действия внутри метода.

Как обычно бывает в CLR, это означает две слегка отличающиеся вещи, в зависимости от того, является переменная экземпляром типа значения (структуры) или же объекта (класса).

Когда экземпляр значения передается по ссылке, копия значения из вызывающего кода не создается. Это подобно передаче параметра как указателя в С++, несмотря на то, что обращение к методам и полям переменной производится точно так же, как к аргументам-значениям. Когда экземпляр объекта (ссылки) передается по ссылке, никакой копии переменной не создается.

Фактически переменная ведет себя подобно указателю С++ на ссылочную переменную, что в С++ выглядит как указатель на указатель. Вдобавок верификатор проверяет, чтобы переменная, на которую ссылается параметр ref, имела определенное присвоенное значение перед вызовом метода.

Рассмотрим некоторые примеры применения полной нотации ref-параметров:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
public struct MyStruct
{
public int val;
}
public class EntryPoint
{
static void Main()  {
MyStruct myValue = new MyStruct ();
myValue.val = 10;
PassByValue ( myValue );
Console.WriteLine ( "Результат PassByValue: myValue.val = {0}",
myValue.val );
PassByRef ( ref myValue );
Console.WriteLine ( "Результат PassByRef: myValue.val = {0}", myValue.val );
}
static void PassByValue ( MyStruct myValue )  {
myValue.val = 50;
}
static void PassByRef ( ref MyStruct myValue )  {
myValue.val = 42;
}

В примере содержатся два метода: PassByValue и PassByRef. Оба метода модифицируют поле экземпляра типа значения, переданного им.

Однако, как доказывает приведенный ниже вывод, метод PassByValue модифицирует локальную копию, в то время как метод PassByRef модифицирует экземпляр из вызывающего кода:

1
2
Результат PassByValue: myValue.val = 10
Результат PassByRef: myValue.val = 42

Кроме того, обратите внимание, что в точке вызова метода PassByRef требуется ключевое слово ref. Это необходимо, потому что метод может быть перегружен на основе присутствия или отсутствия ключевого слова ref. Другими словами, другой метод PassByRef мог бы также принимать MyStruct по значению, а не по ссылке. Плюс к этому обязательное применение ключевого слова ref в точке вызова облегчает чтение кода.

Теперь рассмотрим пример, в котором вместо типа значения используется объект:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System;
public class EntryPoint
{
static void Main()  {
object myObject = new Object ();
Console.WriteLine ( "myObject.GetHashCode () == {0}",
myObject.GetHashCode () );
PassByRef ( ref myObject );
Console.WriteLine ( "myObject.GetHashCode () == {0}", myObject.GetHashCode()  );
}
static void PassByRef( ref object myObject )  {
// Присвоить новый экземпляр этой переменной myObject = new Object();
}
}

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

В предыдущем методе PassByRef переданная ссылка переустанавливается на новый экземпляр объекта. Исходный объект остается без ссылок, и потому готов к тому, чтобы его обработал сборщик мусора. Для получения доказательств, что новая переменная myObject ссылается на два разных экземпляра в точке вызова и в точке, следующей за вызовом, результаты вызовов myObject.GetHashCode отправляются на консоль.

Полученный в результате вывод показан ниже:

1
2
myObject.GetHashCode() == 46104728
myObject.GetHashCode () == 12289376

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

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100