Тип данных SByte (Visual Basic)
Содержит 8-разрядные (1-байтовые) целые числа со знаком в диапазоне от –128 до 127.
Комментарии
SByte Используйте тип данных для хранения целочисленных значений, для которых не требуется полная ширина Integer данных или даже половина ширины Short данных . В некоторых случаях среда CLR может иметь возможность тесно упаковывать SByte переменные и экономить потребление памяти.
Значение по умолчанию для типа SByte — 0.
Литеральные назначения
Переменную SByte можно объявить и инициализировать, назначив ей десятичный литерал, шестнадцатеричный литерал, восьмеричный литерал или (начиная с Visual Basic 2017) двоичный литерал.
В следующем примере целые числа, равные -102, представленные как десятичные, шестнадцатеричные и двоичные литералы, назначаются значениям SByte . В этом примере требуется выполнить компиляцию с параметром компилятора /removeintchecks .
Dim sbyteValue1 As SByte = -102 Console.WriteLine(sbyteValue1) Dim sbyteValue4 As SByte = &H9A Console.WriteLine(sbyteValue4) Dim sbyteValue5 As SByte = &B1001_1010 Console.WriteLine(sbyteValue5) ' The example displays the following output: ' -102 ' -102 ' -102
Префикс &h или &H используется для обозначения шестнадцатеричного литерала, префикса &b или &B для обозначения двоичного литерала и префикса &o или &O для обозначения восьмеричного литерала. У десятичных литералов префиксов нет.
Начиная с Visual Basic 2017, вы также можете использовать символ _ подчеркивания в качестве разделителя цифр для повышения удобочитаемости, как показано в следующем примере.
Dim sbyteValue3 As SByte = &B1001_1010 Console.WriteLine(sbyteValue3) ' The example displays the following output: ' -102
Начиная с Visual Basic 15.5, вы также можете использовать символ подчеркивания ( _ ) в качестве начального разделителя между префиксом и шестнадцатеричными, двоичными или восьмеричной цифрами. Пример:
Dim number As SByte = &H_F9
Чтобы использовать символ подчеркивания в качестве начального разделителя, необходимо добавить следующий элемент в файл проекта Visual Basic (*.vbproj):
Если целочисленный литерал выходит за пределы диапазона SByte (то есть, если он меньше SByte.MinValue или больше SByte.MaxValue), возникает ошибка компиляции. Если целочисленный литерал не имеет суффикса, выводится целое число . Если целочисленный литерал находится за пределами Integer диапазона типа, выводится значение Long . Это означает, что в предыдущих примерах числовые литералы 0x9A и 0b10011010 интерпретируются как 32-разрядные целые числа со знаком со значением 156, которое превышает SByte.MaxValue. Чтобы успешно скомпилировать такой код, который присваивает целое число SByte без десятичного разряда , можно выполнить одно из следующих действий:
- Отключите проверки целочисленных границ путем компиляции с помощью параметра компилятора /removeintchecks .
- Используйте символ типа для явного определения литерального значения, которое необходимо присвоить SByte . В следующем примере отрицательное литеральное Short значение присваивается объекту SByte . Обратите внимание, что для отрицательных чисел должен быть задан бит высокого порядка в слове числового литерала. В нашем примере это бит 15 литерального Short значения.
Dim sByteValue1 As SByte = &HFF_9As Dim sByteValue2 As SByte = &B1111_1111_1001_1010s Console.WriteLine(sByteValue1) Console.WriteLine(sByteValue2)
Советы по программированию
- Соответствие ТРЕБОВАНИЯМ CLS. Тип SByte данных не является частью CLS , поэтому CLS-совместимый код не может использовать компонент, который его использует.
- Расширение. Тип SByte данных расширяется до Short , Integer , Long , Decimal , Single и Double . Это означает, что вы можете выполнить преобразование SByte в любой из этих типов без возникновения System.OverflowException ошибок.
- Символы типов. SByte не имеет символа литерального типа или символа типа идентификатора.
- Тип Framework. В .NET Framework данный тип соответствует структуре System.SByte.
См. также раздел
- System.SByte
- Типы данных
- Type Conversion Functions
- Сводка по преобразованию
- Тип данных Short
- Целочисленный тип данных
- Тип данных Long
- Эффективное использование типов данных
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Sbyte c что это
Все, что необходимо начинающему и опытному программисту
Типы данных.
В этом разделе мы поговорим о типах данных языка C#. Не скроем, что вы найдете здесь массу сюрпризов. Начнем с того, что все встроенные типы данных являются синонимами для соответствующих структур (в некоторых случаях классов), определенных в пространстве имен System. Это означает, что каждая объявленная вами переменная является объектом соответствующей структуры или класса (подробнее о структурах и классах читайте в следующих уроках). Например, каждый числовой тип данных имеет поля MinValue и MaxValue, хранящие соответственно минимальное и максимальное возможные значения для данного типа (см. практические примеры в этом уроке).
Представляем вашему вниманию таблицу, содержащую встроенные типы данных языка C# и соответствующие им структуры или классы пространства имен System.
| C# тип | .NET Framework тип | Количество бит | Суффикс, используемый в литералах | Описание |
|---|---|---|---|---|
| bool | System.Boolean | 8 | — | Логический тип, может принимать только два значения: true и false |
| byte | System.Byte | 8 | — | Беззнаковый байт |
| sbyte | System.SByte | 8 | — | Знаковый байт |
| char | System.Char | 16 | — | Символ Unicode |
| decimal | System.Decimal | 128 | m, M | Десятичное число с фиксированной точностью |
| double | System.Double | 64 | d, D | Число с плавающей запятой |
| float | System.Single | 32 | f, F | Число с плавающей запятой |
| int | System.Int32 | 32 | — | Целое знаковое число |
| uint | System.UInt32 | 32 | u, U | Целое беззнаковое число |
| long | System.Int64 | 64 | l, L | Целое знаковое число |
| ulong | System.UInt64 | 64 | ul, uL, UL, Ul, lu, lU, LU, Lu | Целое беззнаковое число |
| object | System.Object | — | — | Базовый тип данных, все остальные типы являются производными от него |
| short | System.Int16 | 16 | — | Целое знаковое число |
| ushort | System.UInt16 | 16 | — | Целое беззнаковое число |
| string | System.String | — | — | Строка символов Unicode |
Из перечисленных имен System.Object и System.String являются классами, остальные структурами. Поэтому объекты типа string и object называются ссылочными типами, а остальные структурными. Ссылочные и структурные типы будут подробно рассмотрены в следующих уроках. В этом уроке мы всего лишь отметим основную разницу между ними.
Объект ссылочного типа создается в куче, а объект структурного типа создается в стеке. В том случае, если структурный тип присваивается объекту типа object, в куче создается временный объект, имитирующий поведение ссылочного. В этот временный объект копируются данные из структурного, а сам объект помечается специальной отметкой, чтобы система знала к какому типу он относится. Этот процесс называется упаковкой (boxing), обратный процесс называется распаковкой (unboxing).
Кстати, в языке C# отсутствует понятие указателя .
Приведение типов.
Неявно приводить можно:
| Тип данных | неявно приводится к |
|---|---|
| sbyte | short, int, long, float, double, decimal |
| byte | short, ushort, int, uint, long, ulong, float, double, decimal |
| short | int, long, float, double, decimal |
| ushort | int, uint, long, ulong, float, double, decimal |
| int | long, float, double, decimal |
| uint | long, ulong, float, double, decimal |
| long | float, double, decimal |
| ulong | float, double, decimal |
| char | ushort, int, uint, long, ulong, float, double, decimal |
| float | double |
****** константы типа int можно присваивать переменным типов sbyte, byte, short, ushort, uint, или ulong, в случае, если они могут их «съесть». ******
Явно приводить нужно:
| Тип данных | явно приводится к |
|---|---|
| sbyte | byte, ushort, uint, ulong, char |
| byte | sbyte, char |
| short | sbyte, byte, ushort, uint, ulong, char |
| ushort | sbyte, byte, short, char |
| int | sbyte, byte, short, ushort, uint, ulong, char |
| uint | sbyte, byte, short, ushort, int, char |
| long | sbyte, byte, short, ushort, int, uint, ulong, char |
| ulong | sbyte, byte, short, ushort, int, uint, long, or char |
| char | sbyte, byte, short |
| float | sbyte, byte, short, ushort, int, uint, long, ulong, char, decimal |
| double | sbyte, byte, short, ushort, int, uint, long, ulong, char, float, decimal |
| decimal | sbyte, byte, short, ushort, int, uint, long, ulong, char, float, or double |
За более полной информацией можно, как всегда, обратиться в MSDN.
Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru
Sbyte c что это
Я определил несколько целочисленных переменных с ключевым словом int и использовал заключенные в кавычки строки, так что вы уже знакомы с двумя поддерживаемыми С# типами данных. На самом деле в С# поддерживаются восемь целочисленных типов данных:
Целочисленные типы данных C#
| Количество бит | Со знаком | Без знака |
| 8 | sbyte | byte |
| 16 | short | ushort |
| 32 | int | uint |
| 64 | long | ulong |
Кроме того, в С# поддерживаются два типа данных с плавающей точкой, float и double , соответствующие стандарту ANSI/IEEE 754-1985 — IEEE Standard for Binary Floating-Point Arithmetic (стандарт IEEE двоичной арифметики с плавающей точкой). Количество бит, используемое порядком и мантиссой типов float и double , таково:
Количество бит, используемое типами данных С# с плавающей точкой
| Тип С# | Порядок | Мантисса | Всего бит |
| float | 8 | 24 | 32 |
| double | 11 | 53 | 64 |
Кроме того, в С# поддерживается тип decimal , использующий 128 бит для хранения данных. В состав числа этого типа входят 96-битная мантисса и десятичный масштабирующий множитель от 0 до 28. Тип данных decimal обеспечивает точность около 28 десятичных знаков. Он удобен для хранения и выполнения вычислений над числами с фиксированным количеством десятичных знаков, например, денежных сумм или процентных ставок. Я подробней рассмотрю тип decimal , работу с числами и математические вычисления в С# в приложении Б.
Если в тексте программы на С# попадется число 3.14, компилятор будет считать, что оно имеет тип double . Чтобы указать, что его тип float или decimal , используйте для типа float суффикс f а для decimal — суффикс m .
Вот небольшая программа, показывающая минимальное и максимальное значения каждого из одиннадцати числовых типов данных.
//------------------------------------------- // MinAndMax.cs (C) 2001 by Charles Petzold //------------------------------------------- using System; class MinAndMax < public static void Main() < Console.WriteLine("sbyte: to ", sbyte.MinValue, sbyte.MaxValue); Console.WriteLine("byte: to ", byte.MinValue, byte.MaxValue); Console.WriteLine("short: to ", short.MinValue, short.MaxValue); Console.WriteLine("ushort: to ", ushort.MinValue, ushort.MaxValue); Console.WriteLine("int: to ", int.MinValue, int.MaxValue); Console.WriteLine("uint: to ", uint.MinValue, uint.MaxValue); Console.WriteLine("long: to ", long.MinValue, long.MaxValue); Console.WriteLine("ulong: to ", ulong.MinValue, ulong.MaxValue); Console.WriteLine("float: to ", float.MinValue, float.MaxValue); Console.WriteLine("double: to ", double.MinValue, double.MaxValue); Console.WriteLine("decimal: to ", decimal.MinValue, decimal.MaxValue); > >
Как вы заметили, я поставил после каждого типа данных точку и слова MinValue или MaxValue . Эти два идентификатора являются полями структуры. К концу главы все, что делает эта программа, станет для вас понятным, а пока что просто взглянем на результаты ее выполнения:
sbyte: -128 to 127 byte: 0 to 255 short: -32768 to 32767 ushort: 0 to 65535 int: -2147483648 to 2147483647 uint: 0 to 4294967295 long: -9223372036854775808 to 9223372036854775807 ulong: 0 to 18446744073709551615 float: -3.402823E+38 to 3.402823E+38 double: -1.79769313486232E+308 to 1.79769313486232Е+308 decimal: -79228162514264337593543950335 to 79228162514264337593543950335
В С# поддерживается также тип bool , который может принимать только одно из двух значений: true или false , являющихся ключевыми словами С#. Результаты операций сравнения ( == , != , < , >, = ) — значения типа bool . Можно также описать данные типа bool явно. Приведение типа bool к целочисленным типам допускается ( true преобразуется в 1, а false — в 0), но оно должно быть явно указано в коде.
Тип данных char служит для хранения одного символа, a string — для хранения строк из нескольких символов. Тип данных char отличается от целочисленных типов, и его не следует путать с типами sbyte или byte . К тому же переменные типа char занимают 16 бит (но это не значит, что его можно путать с short или ushort ).
Тип char — 16-битный, так как С# использует кодировку Unicode 1 вместо ASCII. Вместо 7-битного представления символов в базовом варианте ASCII и 8 бит на символ в расширенных наборах символов, ставших общепринятыми на компьютерах, в Unicode для кодировки одного символа используется целых 16 бит. Это позволяет отобразить все буквы, условные обозначения и другие символы всех письменностей мира, которые могут использоваться при работе с компьютером. Unicode является расширением кодировки ASCII. Его первые 128 символов совпадают с символами ASCII.
Типы данных не обязательно определять в начале метода. Как и в C++, можно определить типы данных в том месте метода, где они потребовались.
Переменную можно определить и сразу же инициализировать:
string str = "Hello, World!";
Как только переменной типа string присвоено значение, ее отдельные символы нельзя изменить, однако можно присвоить ей новое значение. Строки не заканчиваются нулем, а количество символов в переменной типа string можно определить так:
str.Length
Length является свойством типа данных string ; концепцию свойств я опишу дальше в этой главе. В приложении В содержится подробная информация по работе со строками в С#.
Чтобы описать переменную-массив, поставьте после типа данных пустые квадратные скобки:
float[] arr;
Тип данных переменной arr — массив чисел с плавающей точкой, но на самом деле arr — это указатель. В языке С# массив является ссылочным типом ( reference type ). Это относится и к строке. Другие типы, о которых я рассказывал ранее, являются размерными ( value types ).
Значение переменной arr при первоначальном определении — null . Для выделения памяти массиву нужно воспользоваться оператором new и указать количество элементов в массиве:
arr = new float[3];
Можно также применить сочетание двух приведенных выше операторов:
float[] arr = new float[3];
Кроме того, при описании массива можно инициализировать его элементы:
float[] arr = new float[3] < 3.14f, 2.17f, 100 >;
Количество инициализирующих значений должно совпадать с объявленным размером массива. При инициализации массива можно опустить размер:
float[] arr = new float[] < 3.14f, 2.17f, 100 >;
и даже — оператор new .
float[] arr = < 3.14f, 2.17f, 100 >;
В дальнейшем в программе можно присвоить переменной arr массив типа float другого размера:
arr = new float[5];
При этом выделяется память для хранения пяти значений типа float , каждое из этих значений первоначально равно 0.
Вы можете спросить: «А что случилось с первым блоком памяти, выделенным для трех значений типа float ?» В С# нет оператора delete . Поскольку на исходный блок памяти больше не ссылается ни одна из переменных программы, он становится объектом сборки мусора ( garbage collection ). В какой-то момент Common Language Runtime освободит память, изначально выделенную массиву.
Как и в случае строк, количество элементов массива можно определить, используя выражение:
arr.Length;
Кроме того, С# позволяет создавать многомерные и невыровненные (jagged) массивы, являющиеся массивами массивов.
Если не нужно взаимодействие с кодом, написанным на другом языке, указатели в программах на С# требуются редко. По умолчанию параметры передаются методам по значению. Это означает, что метод может как угодно изменять параметр, а значение параметра в вызывающем методе не изменится. Чтобы изменить такое поведение параметров, можно использовать ключевые слова ref (reference — ссылка) или out , Например, определить метод, изменяющий передаваемую в качестве параметра переменную, можно так:
void AddFive(ref int i)
А метод, присваивающий переменной значение, выглядит так:
void SetToFive(out int i)
В первом примере переменной i необходимо присвоить значение перед вызовом AddFive , тогда метод AddFive сможет изменить ее значение. Во втором — i при вызове метода может не иметь никакого значения.
Важную роль в С# и .NET Framework играют перечисления. Многие константы .NET Framework определены как перечисления. Приведем пример из пространства имен SystemIO :
public enum FileAccess
Перечисления всегда являются целочисленными типами данных, по умолчанию они имеют тип int . Если не указать значение явно (в данном примере для Read оно указано), первому элементу перечисления присваивается нулевое значение. Следующим элементам присваиваются значения в порядке возрастания.
FileAccess можно использовать при работе с несколькими классами файлового ввода-вывода. (Файловый ввод-вывод подробно рассмотрен в приложении А). Необходимо указывать имя перечисления, затем, через точку имя элемента:
file.Open(FileMode.CreateNew, FileAccess.ReadWrite)
FileMode — это еще одно перечисление класса SystemIO . Если эти два перечисления в методе Open поменять местами, компилятор сообщит об ошибке. Перечисления помогают программисту избегать ошибок, связанных с константами.
1 Дополнительную информацию можно получить на Web-странице http://www.unicode.org или в The Unicode Consortium, The Unicode Standard Version 3.0 (Reading, Mass.: Addison-Wesley, 2000).
Sbyte c что это
Ранее мы рассматривали следующие элементарные типы данных: int, byte, double, string, object и др. Также есть сложные типы: структуры, перечисления, классы. Все эти типы данных можно разделить на типы значений, еще называемые значимыми типами, (value types) и ссылочные типы (reference types). Важно понимать между ними различия.
- Целочисленные типы ( byte, sbyte, short, ushort, int, uint, long, ulong )
- Типы с плавающей запятой ( float, double )
- Тип decimal
- Тип bool
- Тип char
- Перечисления enum
- Структуры ( struct )
- Тип object
- Тип string
- Классы ( class )
- Интерфейсы ( interface )
- Делегаты ( delegate )
В чем же между ними различия? Для этого надо понять организацию памяти в .NET. Здесь память делится на два типа: стек и куча (heap). Параметры и переменные метода, которые представляют типы значений, размещают свое значение в стеке. Стек представляет собой структуру данных, которая растет снизу вверх: каждый новый добавляемый элемент помещается поверх предыдущего. Время жизни переменных таких типов ограничено их контекстом. Физически стек — это некоторая область памяти в адресном пространстве.
Когда программа только запускается на выполнение, в конце блока памяти, зарезервированного для стека устанавливается указатель стека. При помещении данных в стек указатель переустанавливается таким образом, что снова указывает на новое свободное место. При вызове каждого отдельного метода в стеке будет выделяться область памяти или фрейм стека, где будут храниться значения его параметров и переменных.
class Program < static void Main(string[] args) < Calculate(5); >static void Calculate(int t) < int x = 6; int y = 7; int z = y + t; >>
При запуске такой программы в стеке будут определяться два фрейма — для метода Main (так как он вызывается при запуске программы) и для метода Calculate:

При вызове этого метода Calculate в его фрейм в стеке будут помещаться значения t, x, y и z. Они определяются в контексте данного метода. Когда метод отработает, область памяти, которая выделялась под стек, впоследствии может быть использована другими методами.
Причем если параметр или переменная метода представляет тип значений, то в стеке будет храниться непосредсвенное значение этого параметра или переменной. Например, в данном случае переменные и параметр метода Calculate представляют значимый тип — тип int, поэтому в стеке будут храниться их числовые значения.
Ссылочные типы хранятся в куче или хипе, которую можно представить как неупорядоченный набор разнородных объектов. Физически это остальная часть памяти, которая доступна процессу.
При создании объекта ссылочного типа в стеке помещается ссылка на адрес в куче (хипе). Когда объект ссылочного типа перестает использоваться, в дело вступает автоматический сборщик мусора: он видит, что на объект в хипе нету больше ссылок, условно удаляет этот объект и очищает память — фактически помечает, что данный сегмент памяти может быть использован для хранения других данных.
Так, в частности, если мы изменим метод Calculate следующим образом:
static void Calculate(int t)
То теперь значение переменной x будет храниться в куче, так как она представляет ссылочный тип object, а в стеке будет храниться ссылка на объект в куче.

Составные типы
Теперь рассмотим ситуацию, когда тип значений и ссылочный тип представляют составные типы — структуру и класс:
State state1 = new State(); // State — структура, ее данные размещены в стеке Country country1 = new Country(); // Country — класс, в стек помещается ссылка на адрес в хипе // а в хипе располагаются все данные объекта country1 struct State < public int x; public int y; >class Country
Здесь в методе Main в стеке выделяется память для объекта state1. Далее в стеке создается ссылка для объекта country1 ( Country country1 ), а с помощью вызова конструктора с ключевым словом new выделяется место в хипе ( new Country() ). Ссылка в стеке для объекта country1 будет представлять адрес на место в хипе, по которому размещен данный объект..

Таким образом, в стеке окажутся все поля структуры state1 и ссылка на объект country1 в хипе.
Но, допустим, в структуре State также определена переменная ссылочного типа Country. Где она будет хранить свое значение, если она определена в типе значений?
State state1 = new State(); Country country1 = new Country(); struct State < public int x; public int y; public Country country; public State() < x = 0; y = 0; country = new Country(); >> class Country
Значение переменной state1.country также будет храниться в куче, так как эта переменная представляет ссылочный тип:

Копирование значений
Тип данных надо учитывать при копировании значений. При присвоении данных объекту значимого типа он получает копию данных. При присвоении данных объекту ссылочного типа он получает не копию объекта, а ссылку на этот объект в хипе. Например:
State state1 = new State(); // Структура State State state2 = new State(); state2.x = 1; state2.y = 2; state1 = state2; state2.x = 5; // state1.x=1 по-прежнему Console.WriteLine(state1.x); // 1 Console.WriteLine(state2.x); // 5 Country country1 = new Country(); // Класс Country Country country2 = new Country(); country2.x = 1; country2.y = 4; country1 = country2; country2.x = 7; // теперь и country1.x = 7, так как обе ссылки и country1 и country2 // указывают на один объект в хипе Console.WriteLine(country1.x); // 7 Console.WriteLine(country2.x); // 7
Так как state1 — структура, то при присвоении state1 = state2 она получает копию структуры state2. А объект класса country1 при присвоении country1 = country2; получает ссылку на тот же объект, на который указывает country2. Поэтому с изменением country2, так же будет меняться и country1.
Ссылочные типы внутри типов значений
Теперь рассмотрим более изощренный пример, когда внутри структуры у нас может быть переменная ссылочного типа, например, какого-нибудь класса:
State state1 = new State(); State state2 = new State(); state2.country.x = 5; state1 = state2; state2.country.x = 8; // теперь и state1.country.x=8, так как state1.country и state2.country // указывают на один объект в хипе Console.WriteLine(state1.country.x); // 8 Console.WriteLine(state2.country.x); // 8 struct State < public int x; public int y; public Country country; public State() < x = 0; y = 0; country = new Country(); // выделение памяти для объекта Country >> class Country
Переменные ссылочных типов в структурах также сохраняют в стеке ссылку на объект в хипе. И при присвоении двух структур state1 = state2; структура state1 также получит ссылку на объект country в хипе. Поэтому изменение state2.country повлечет за собой также изменение state1.country.

Объекты классов как параметры методов
Организацию объектов в памяти следует учитывать при передаче параметров по значению и по ссылке. Если параметры методов представляют объекты классов, то использование параметров имеет некоторые особенности. Например, создадим метод, который в качестве параметра принимает объект Person:
Person p = new Person < name = "Tom", age = 23 >; ChangePerson(p); Console.WriteLine(p.name); // Alice Console.WriteLine(p.age); // 23 void ChangePerson(Person person) < // сработает person.name = "Alice"; // сработает только в рамках данного метода person = new Person < name = "Bill", age = 45 >; Console.WriteLine(person.name); // Bill > class Person
При передаче объекта класса по значению в метод передается копия ссылки на объект. Эта копия указывает на тот же объект, что и исходная ссылка, потому мы можем изменить отдельные поля и свойства объекта, но не можем изменить сам объект. Поэтому в примере выше сработает только строка person.name = «Alice» .
А другая строка person = new Person < name = "Bill", age = 45 >создаст новый объект в памяти, и person теперь будет указывать на новый объект в памяти. Даже если после этого мы его изменим, то это никак не повлияет на ссылку p в методе Main, поскольку ссылка p все еще указывает на старый объект в памяти.
Но при передаче параметра по ссылке (с помощью ключевого слова ref ) в метод в качестве аргумента передается сама ссылка на объект в памяти. Поэтому можно изменить как поля и свойства объекта, так и сам объект:
Person p = new Person < name = "Tom", age = 23 >; ChangePerson(ref p); Console.WriteLine(p.name); // Bill Console.WriteLine(p.age); // 45 void ChangePerson(ref Person person) < // сработает person.name = "Alice"; // сработает person = new Person < name = "Bill", age = 45 >; > class Person
Операция new создаст новый объект в памяти, и теперь ссылка person (она же ссылка p из метода Main) будет указывать уже на новый объект в памяти.