Язык программирования C#9 и платформа .NET5
Assigning value typesX = 10, Y = 10X = 10, Y = 10=> Changed p1.XX = 100, Y = 10X = 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.XAssigning reference typesX = 10, Y = 10X = 10, Y = 10=> Changed p1.XX = 100, Y = 10X = 100, Y = 10Использование типов значений, содержащих ссылочные типы
Теперь, когда вы лучше понимаете базовые отличия между типами значений и ссылочными типами, давайте обратимся к более сложному примеру. Предположим, что имеется следующий ссылочный тип (класс), который поддерживает информационную строку (
), устанавливаемую с применением специального конструктора:InfoStringclass ShapeInfo{public string InfoString;public ShapeInfo(string info){InfoString = info;}}Далее представим, что переменная типа
должна содержаться внутри типа значения по имениShapeInfo. Кроме того, в типеRectangleпредусмотрен специальный конструктор, который позволяет вызывающему коду указывать значение для внутренней переменной-члена типаRectangle. Вот полное определение типаShapeInfo:Rectanglestruct Rectangle{// Структура Rectangle содержит член ссылочного типа.public ShapeInfo RectInfo;public int RectTop, RectLeft, RectBottom, RectRight;public Rectangle(string info, int top, int left, int bottom, int right){RectInfo = new ShapeInfo(info);RectTop = top; RectBottom = bottom;RectLeft = left; RectRight = right;}public void Display(){Console.WriteLine("String = {0}, Top = {1}, Bottom = {2}, " +"Left = {3}, Right = {4}",RectInfo.InfoString, RectTop, RectBottom, RectLeft, RectRight);}}Здесь ссылочный тип содержится внутри типа значения. Возникает важный вопрос: что произойдет в результате присваивания одной переменной типа
другой переменной того же типа? Учитывая то, что уже известно о типах значений, можно корректно предположить, что целочисленные данные (которые на самом деле являются структурой —Rectangle)должны быть независимой сущностью для каждой переменнойSystem.Int32. Но что можно сказать о внутреннем ссылочном типе? Будет ли полностью скопировано состояние этого объекта или же только ссылка на него? Чтобы получить ответ, определите следующий метод и вызовите его:Rectanglestatic void ValueTypeContainingRefType(){