- •Классы и структуры
- •Функции-члены
- •Передача параметров в методы
- •Параметры ref
- •Параметры out
- •Свойства
- •Свойства, доступные только для чтения и только для записи
- •Модификаторы доступа для свойств
- •Автоматически реализуемые свойства
- •Замечание о встраивании
- •Индексаторы
- •Тип_элемента this[int индекс]
- •Листинг 1.
- •Листинг 2.
- •Листинг 3.
- •Листинг 4.
- •Конструкторы
- •Статические конструкторы
- •Вызов одних конструкторов из других
- •Поля readonly
- •Анонимные типы
- •Структуры
- •Структуры это типы значений
- •Структуры и наследование
- •Конструкторы структур
- •Частичные классы
- •Статические классы
- •Класс Object
- •Методы System.Object
- •Метод ToString()
- •Расширяющие методы
Передача параметров в методы
В общем случае параметры могут передаваться методу 'либо по значению, либо по ссылке. Когда переменная передается по ссылке, вызываемый метод получает саму переменную, поэтому любые изменения, которым она подвергнется внутри метода, останутся в силе после его завершения. Но если переменная передается по значению, вызываемый метод получает копию этой переменной, а это значит, что все изменения в ней по завершении метода будут утеряны. Для сложных типов данных передача по ссылке более эффективна из-за большого объема данных, который приходится копировать при передаче по значению.
Если не указано обратное, то в С# все параметры передаются по значению. Однако нужно быть осторожным с пониманием этого в отношении ссылочных типов. Поскольку переменная ссылочного типа содержит лишь ссылку на объект, то именно ссылка будет скопирована при передаче параметра, а не сам объект.. То есть изменения, произведенные в самом объекте, сохранятся. В отличие от этого, переменные типа значений действительно содержат данные, поэтому в метод передается копия самих данных. Например, int передается в метод по значению, и любые изменения, которые сделает метод в этом int, не изменят значения исходного объекта. В противоположность этому, если в метод передается массив или любой другой ссылочный тип, такой как класс, и метод использует эту ссылку для изменения значения в массиве, то это новое значение будет отражено в исходном объекте массива.
Сказанное выше иллюстрируется в следующем примере, ParameterTest.cs.
ParameterTest.cs
using System;
namespace Wrox
{
class ParameterTest
{
static void SomeFunction(int[] ints, int i)
{
ints[0] = 100;
i = 100;
}
public static int Main()
{
int i = 0;
int[] ints = { 0, 1, 2, 4, 8 };
// Display the original values
Console.WriteLine("i = " + i);
Console.WriteLine("ints[0] = " + ints[0]);
Console.WriteLine("Calling SomeFunction...");
// After this method returns, ints will be changed,
// but i will not
SomeFunction(ints, i);
Console.WriteLine("i = " + i);
Console.WriteLine("ints[0] = " + ints[0]);
return 0;
}
}
}
Ниже показан вывод этой программы:
ParameterTest.exe i = 0
ints[0) = 0
Вызов SomeFunction...
i = 0
ints[0] = 100
Обратите внимание, что значение i осталось неизменным, но измененные значения в ints также изменились в исходном массиве.
Поведение строк также отличается. Дело в том, что строки являются неизменными (изменение значения строки то приводит к созданию совершенно новой строки), поэтому строки не демонстрируют поведение, характерное для ссылочных типов. Любые изменения, проведенные в строке внутри метода, не влияют на исходную строку. Этот момент более подробно обсуждается в разделе 6.9.
Параметры ref
Как уже упоминалось, по умолчанию параметры передаются по значению. Тем не менее, можно принудительно передавать значения по ссылке, для чего используется ключевое слово ref. Если параметр передается в метод, и входной аргумент этого метода снабжен префиксом ref, то любые изменения этой переменной, которые сделает метод, отразятся на исходном объекте:
static void SomeFunction (int [ ] ints, ref int i)
{
ints[0] = 100;
i = 100;
// изменение i сохранится после завершения SomeFunction ()
}
Ключевое слово ref также должно быть указано при вызове метода:
SomeFunction(ints, ref i);
И, наконец, также важно понимать, что С# распространяет требование инициализации на параметры, переданные методу. Любая переменная должна быть инициализирована прежде, чем она будет передана в метод, независимо от того, передается она по значению или ссылке.