// Локальные структуры извлекаются из стека,

// когда метод возвращает управление.

static void LocalValueTypes()

{

  // Вспомните, что int - на самом деле структура System.Int32.

  int i = 0;

  // Вспомните, что Point - в действительности тип структуры.

  Point p = new Point();

} // Здесь i и р покидают стек!

<p id="AutBody_Root179">Использование типов значений ссылочных типов и операции присваивания</p>

Когда переменная одного типа значения присваивается переменной другого типа значения, выполняется почленное копирование полей данных. В случае простого типа данных, такого как System.Int32, единственным копируемым членом будет числовое значение. Однако для типа Point в новую переменную структуры будут копироваться значения полей X и Y. В целях демонстрации создайте новый проект консольного приложения по имени FunWithValueAndReferenceTypes и скопируйте предыдущее определение Point в новое пространство имен, после чего добавьте к операторам верхнего уровня следующую локальную функцию:

// Присваивание двух внутренних типов значений дает

// в результате две независимые переменные в стеке.

static void ValueTypeAssignment()

{

  Console.WriteLine("Assigning value types\n");

  Point p1 = new Point(10, 10);

  Point p2 = p1;

  // Вывести значения обеих переменных Point.

  p1.Display();

  p2.Display();

  // Изменить pl.X и снова вывести значения переменных.

  // Значение р2.Х не изменилось.

  p1.X = 100;

  Console.WriteLine("\n=> Changed p1.X\n");

  p1.Display();

  p2.Display();

}

Здесь создается переменная типа Point(p1), которая присваивается другой переменной типа Point(р2). Поскольку Point — тип значения, в стеке находятся две копии Point, каждой из которых можно манипулировать независимым образом. Поэтому при изменении значения p1.X значение р2.X остается незатронутым:

Assigning value types

X = 10, Y = 10

X = 10, Y = 10

=> Changed p1.X

X = 100, Y = 10

X = 10, Y = 10

По контрасту с типами значений, когда операция присваивания применяется к переменным ссылочных типов (т.е. экземплярам всех классов), происходит перенаправление на то, на что ссылочная переменная указывает в памяти. В целях иллюстрации создайте новый класс по имени PointRef с теми же членами, что и у структуры Point, но только переименуйте конструктор в соответствии с именем данного класса:

// Классы всегда являются ссылочными типами.

class PointRef

{

  // Те же самые члены, что и в структуре Point...

  // Не забудьте изменить имя конструктора на PointRef!

  public PointRef(int xPos, int yPos)

  {

    X = xPos;

    Y = yPos;

  }

}

Задействуйте готовый тип PointRef в следующем новом методе. Обратите внимание, что помимо использования класса PointRef вместо структуры Point код идентичен коду метода ValueTypeAssignment():

static void ReferenceTypeAssignment()

{

  Console.WriteLine("Assigning reference types\n");

  PointRef p1 = new PointRef(10, 10);

  PointRef p2 = p1;

  // Вывести значения обеих переменных PointRef.

  p1.Display();

  p2.Display();

  // Изменить pl.X и снова вывести значения.

  p1.X = 100;

  Console.WriteLine("\n=> Changed p1.X\n");

  p1.Display();

  p2.Display();

}

В рассматриваемом случае есть две ссылки, указывающие на тот же самый объект в управляемой куче. Таким образом, когда значение X изменяется с использованием ссылки p1, изменится также и значение р2.X. Вот вывод, получаемый в результате вызова этого нового метода:

Assigning reference types

X = 10, Y = 10

X = 10, Y = 10

=> Changed p1.X

X = 100, Y = 10

X = 100, Y = 10

Перейти на страницу:

Похожие книги