Главная arrow Язык программирования C# arrow C# Полное руководство Герберт Шилдт arrow Способы передачи аргументов методу C# Полное руководство Герберт Шилдт

Способы передачи аргументов методу C# Полное руководство Герберт Шилдт

Как показывает приведенный выше пример, передача объекта методу по ссылке делается достаточно просто. Но в этом примере показаны не все нюансы данного процесса. В некоторых случаях последствия передачи объекта по ссылке будут отличаться от тех результатов, к которым приводит передача значения обычного типа. Для выяснения причин этих отличий рассмотрим два способа передачи аргументов методу.
Первым способом является вызов по значению. В этом случае значение аргумента копируется в формальный параметр метода. Следовательно, изменения, вносимые в параметр метода, не оказывают никакого влияния на аргумент, используемый для вызова. А вторым способом передачи аргумента является вызов по ссылке. В данном случае параметру метода передается ссылка на аргумент, а не значение аргумента. В методе эта ссылка используется для доступа к конкретному аргументу, указываемому при вызове. Это означает, что изменения, вносимые в параметр, будут оказывать влияние на аргумент, используемый для вызова метода.
По умолчанию в C# используется вызов по значению, а это означает, что копия аргумента создается и затем передается принимающему параметру. Следовательно, при передаче значения обычного типа, например int или double, все, что происходит с параметром, принимающим аргумент, не оказывает никакого влияния за пределами метода. В качестве примера рассмотрим следующую программу.

// Передача аргументов обычных типов по значению.

using System;

class Test {
   /* Этот метод не оказывает никакого влияния на
       аргументы, используемые для его вызова. */
   public void NoChange(int i, int j) {
      i = i + j;
      j = -j;
   }
}

class CallByValue {
   static void Main() {
      Test ob = new Test();

      int a = 15, b = 20;

      Console.WriteLine ("а и b до вызова: " + a + " " + b) ;
      ob.NoChange(a, b);
      Console.WriteLine ("а и b после вызова: " + a + " " + b) ;
   }
}


Вот какой результат дает выполнение этой программы:
   а и b до вызова: 15 20
   а и b после вызова: 15 20

Как видите, операции, выполняемые в методе NoChange (), не оказывают никакого влияния на значения аргументов а и Ь, используемых для вызова данного метода. Это опять же объясняется тем, что параметрам i и j переданы копии значений аргументов а и Ь, а сами аргументы а и b совершенно не зависят от параметров i и j. В частности, присваивание параметру i нового значения не будет оказывать никакого влияния на аргумент а.
Дело несколько усложняется при передаче методу ссылки на объект. В этом случае сама ссылка по-прежнему передается по значению. Следовательно, создается копия ссылки, а изменения, вносимые в параметр, не оказывают никакого влияния на аргумент. (Так, если организовать ссылку параметра на новый объект, то это изменение не повлечет за собой никаких последствий для объекта, на который ссылается аргумент.) Но главное отличие вызова по ссылке заключается в том, что изменения, происходящие с объектом, на который ссылается параметр, окажут влияние на тот объект, на который ссылается аргумент. Попытаемся выяснить причины подобного влияния.
Напомним, что при создании переменной типа класса формируется только ссылка на объект. Поэтому при передаче этой ссылки методу принимающий ее параметр будет ссылаться на тот же самый объект, на который ссылается аргумент. Это означает, что и аргумент, и параметр ссылаются на один и тот же объект и что объекты, по существу, передаются методам по ссылке. Таким образом, объект в методе будет оказывать влияние на объект, используемый в качестве аргумента. Для примера рассмотрим следующую программу:

// Передача объектов по ссылке.

using System;

class Test {
   public int a, b;

   public Test (int i, int j) {
      а = i;
      b = j;
   }
   /* Передать объект. Теперь переменные ob.a и ob.b
      из объекта, используемого в вызове метода, будут
      изменены. */
   public void Change(Test ob) {
      ob.a = ob.a + ob.b;
      ob.b = -ob.b;
   }
}

class CallByRef {
   static void Main() {
      Test ob = new Test (15, 20);

      Console.WriteLine ("ob.a и ob.b до вызова: " + ob.a + " " + ob.b);
     
      ob.Change(ob);

      Console. WriteLine ("ob.a и ob.b после вызова: " + ob.a + " " + ob.b);
   }
}


Выполнение этой программы дает следующий результат:
   ob.a и ob.b до вызова: 15 20
   ob.a и ob.b после вызова: 35 -20

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